Langages/Ruby/Rails/Tests/Cucumber

Un article de Agora2ia.


Sommaire

Présentation

Version 0.1.15

sudo gem install cucumber
cucumber help
  • A destination des non techniciens.
  • Gherkin, le langage dans lequel on écrit les specs, et on peut le faire en français !!!
  • Quand un test échoue, cela remonte jusque la spec / feature concernée.


Installation

git clone git://github.com/aslakhellesoy/cucumber.git
cd cucumber
rake install_gem

Exemples :

cd examples/calculator_ruby_features/


Cucumber for RSpec

Installer les plugins :

gem install rspec rspec-rails cucumber webrat


Prendre la bonne version de Webrat (http://wiki.github.com/aslakhellesoy/cucumber/ruby-on-rails) :

gem sources -a http://gems.github.com
[sudo] gem install aslakhellesoy-webrat


Créer le projet :

rails myproject
cd myproject
script/generate cucumber


Installer le plugin RSpec et RSpec-Rails pour/dans notre application :

ruby script/plugin install git://github.com/dchelimsky/rspec.git
ruby script/plugin install git://github.com/dchelimsky/rspec-rails.git


And Go Go Go !

rake features


Cucumber bundle pour TextMate

http://wiki.github.com/dchelimsky/rspec-rails/home

mkdir -p ~/Library/Application\ Support/TextMate/Bundles/
cd ~/Library/Application\ Support/TextMate/Bundles
git clone git://github.com/bmabey/cucumber-tmbundle.git Cucumber.tmbundle


i18n dans Cucumber

La liste des keywords à connaitre : 20 languages

"fr":
  feature: Fonctionnalité
  scenario: Scénario
  more_examples: Plus d'exemples
  given_scenario: Soit le Scénario
  given: Etant donné
  when: Lorsque
  then: Alors
  and: Et
  but: Mais


Pout passer dans un autre langage, vous pouvez modifier /lib/tasks/cucumber.rake pour y ajouter l'option --language fr  :

$:.unshift(RAILS_ROOT + '/vendor/plugins/cucumber/lib')
require 'cucumber/rake/task'

Cucumber::Rake::Task.new(:features) do |t|
  t.cucumber_opts = "--format pretty --language fr"
end
task :features => 'db:test:prepare'


Séquence à suivre

Etapes successives :

  1. Créer la feature
  2. Créer le steps (*_steps.rb)
  3. Remplir les steps
    1. Le setup avec "Before do"
    2. En utilisant RSpec (.should ==)
    3. Paramétriser (Attention à nommer à l'identique les steps entre feature et steps.rb) : using-fit-tables-in-a-feature
  4. Créer le model (valeur de retour en dur)
  5. Mettre en place la table FIT


BDD

Scenario:

AS A [role]
I WANT [feature]
IN ORDER TO [value]

Step:

GIVEN [situation]
WHEN [action]
THEN [outcom]


Specs exécutables

Nous obtenons des spécifications exécutables : modfiez des mots clefs comme "Scenario" ou "And" (faites une faute d'ortographe)...


Scénario en tableau

Une force de Cucumber est de pouvoir spécifier un scénario sous forme de tableau.

Cela est particulièrement interessant quand on souhaite écrire un scénario qui comporte différentes valeurs numériques comme par exemple pour valider une formule.

Scenario: eat 5 out of 12
   Given there are 12 cucumbers
   When I eat 5 cucumbers
   Then I should have 7 cucumbers

Scenario: eat 5 out of 20
   Given there are 20 cucumbers
   When I eat 5 cucumbers
   Then I should have 15 cucumbers

Devient ainsi :

Scenario Outline: eating
   Given there are <start> cucumbers
   When I eat <eat> cucumbers
   Then I should have <left> cucumbers

   Examples:
      | start | eat | left |
      |  12   |  5  |  7   |
      |  20   |  5  |  15  |

Hello World


Configuration

# /config/environments/test.rb
...
config.gem "webrat", :lib => false, :version => ">=0.4.3"
config.gem "cucumber", :lib => false, :version => ">=0.2.2"
config.gem "cucumber-rails"
config.gem "rspec"
config.gem "rspec-rails"
$ sudo rake gems:install RAILS_ENV=test
$ script/generate cucumber --webrat --rspec       // Generate helper files (step_definitions...)


Ma première feature

It’s really, really recommended that you write your features by hand, however, to get you started you can use the feature generator :

$ ruby script/generate feature Frooble name:string color:string description:text


# /features/manage_articles.feature
Feature: Manage Articles
  In order to make a blog
  As an author
  I want to create and manage articles

  Scenario: Article List
    Given I have articles titles Pizza, Breadsticks
    When I go to the list of articles
    Then I should see "Pizza"
    And I should see "Breadsticks"


$ rake -T cucumber                   // to see the other rake tasks available

or

$ cucumber features -n               // --> One step pending
# /features/step_definitions/article_steps.rb
+++
Given /^I have articles titles (.+)$/ do |titles|
  titles.split(', ').each do |title|
    Article.create!(:title => title)
  end
end


$ cucumber features -n                // --> Article not found !
$ script/generate rspec_model article title:string content:text
$ rake db:migrate
$ rake db:test:clone

$ cucumber features -n                // --> Path of Articles list not found


# /features/support/path.rb
module NavigartionHelpers
  def path_to(page_name)
    case page_name
      ...
    when /the articles list/
      articles_path
  ...


$ cucumber features -n                // --> articles_path method not found

# routes.rb
map.resources :articles


$ cucumber features -n                // --> ArticlesController not found
$ script/generate rspec_controller articles index


$ cucumber features -n                // --> Pizza not found on page

# articles_controller.rb
+++
def index
  @articles = Article.all
end
# index.html.erb
===
<% for article in @articles %>
  <%=h article.title %>
<% end %>
$ cucumber features -n                // --> OK !


Une feature plus complète

# /features/manage_articles.feature
+++
Scenario: Create Valid Article
  Given I have no articles
  And I am on the list of articles
  When I follow "New Article"
  And I fill in "Title" with "Spuds"
  And I fill in "Content" with "Delicious potato wedges!"
  And I press "Crete"
  Then I should see "New article created"
  And I should see "Spuds"
  And I should see "Delicious potato wedges!"
  And I should have 1 article
$ cucumber features -n                // --> 2 undefined steps
# /features/step_definitions/article_steps.rb
+++
Given /^I have no articles$/ do |titles|
  Article.delete_all
end
Given /^I have ([0-9]+) articles$/ do |count|
  Article.count.shoulr == count.to_i
end


$ cucumber features -n                // --> No "New Article" link
# articles_controller.rb
+++
def new
  @article = Article.new
end
# index.html.erb
+++
<p><%= link_to "New article", new_article_path %></p>
# new.html.erb
===
<% form_for @article do |f| %>
  <p>
     <%= f.label :title %><br />
     <%= f.text_field :title %>
   </p>
   <p>
     <%= f.label :content %><br />
     <%= f.text_field :content %>
   </p>
   <p class="button"><%= f.submit "Create" %></p>
<% end %>


$ cucumber features -n                // --> No "Create" action
# articles_controller.rb
+++
def create
  @article = Article.create!(params[:article])
  flash[:notice] = "New article created."
  redirect_to articles_path
end


$ cucumber features -n                // --> No "Create" action
# index.html.erb
===
 <%= flash[:notice] %>
 <% for article in @articles %>
   <p><%=h article.title %></p>
   <p><%=h article.content %></p>
 <% end %>
 <p><%= link_to "New article", new_article_path %></p>


$ cucumber features -n                // --> OK !


Tips

Vérifier l'URL de la page

Se fait en utilisant la variable current_url (attention à distinguer _url et _path) :

Then /^the user see the company information page$/ do
  current_path.should == company_path(@other_company)
  current_url.should == company_url(@other_company)
  page.should have_content(@other_company.company_name)
end


Nettoyer la base de données entre deux scénarios

Voir The Cucumber Book p181 :

  • 10.4 - Cleaning the Database with Transactions : RECOMMANDE !
    • Utiliser gem 'database_cleaner', '0.8.0' dans le Gemfile
    • Puis DatabaseCleaner.strategy = :transaction, Before do DatabaseCleaner.start end et After do DatabaseCleaner.clean end dans features/support/database.rb
  • 10.5 - Cleaning the Database with Truncation


Appeler un step depuis un autre (réutiliser un step)

Utiliser le mot clef step suivit du nom du step :

# /features/step_definitions/authentication_steps.rb

#
# GIVEN
#
Given /^a full configured and signed in user$/ do
   ...
   step "the user submits valid signin information"
   ...
end

#
# WHEN
#
When /^the user submits valid signin information$/ do
   fill_in "session_email",    with: @user.email
   fill_in "session_password", with: @user.password
   click_button "commit_signin"
end

#
# THEN
#

Ressources

  • Beaucoup de ressources sur le site officiel cukes.info
  • Les livres de pragmatic programmers
  • Les screencasts de railscasts (qui datent un peu) et peepcode