Cucumber
   Hussein Morsy und Tanja Otto


             30.06.2009
Heinrich-Heine-Universität Düsseldorf
    Rails User Group Düsseldorf
Über uns

• internes Entwicklerteam von Sales-Lentz
• IBEs für Reisen, Bustickets, Eventtickets
• seit 2006 entwickeln wir mit Ruby on Rails
• Buch Ruby on Rails 2 Galileo Press
  http://www.railsbuch.de
Wer setzt Cucumber in
 seinen Projekten ein?
Aufbau
• Philosophie
• Cucumber Features erstellen
• Cucumber Features automatisieren
• Tabellen, Outlines und weitere Helferleins
• Cucumber installieren und konfigurieren
• Demo
Philosophie
Was ist TDD
• Hauptmerkmal: Test First
• Von Innen nach Aussen
• Red => Green => Refactor
  “Make it green than make it clean”
• TDD ist kein Test-Tool, sondern eine
  Technik für Entwickler
Units

   Views             Views            Views            Views




        Controller       Controller       Controller




Model        Model           Model        Model         Model
TDD-Tools

• Unit-Test-Frameworks in Ruby
 • Test::Unit
 • Shoulda
 • RSpec
 • ...
Ziel von BDD

writing software that matters
Was ist BDD

• BDD ist kein Ersatz für TDD
• TDD ist ein Bestandteil von BDD
• BDD bedeutet outside-in Entwicklung
• Wie ein User mit der App arbeiten möchte
  beeinflusst die Implementierung
• Kundenwünsche stehen an erster Stelle
Outside-In

   Views             Views            Views            Views




        Controller       Controller       Controller




Model        Model           Model        Model         Model
Cucumber
Cucumber


 Applikation
Planung
• Beschreibung der Features bzw.
  Akzeptanzkritieren
• Beschreibung einer Story aus
  Anwendersicht
• Zusammen mit dem Kunden
• Business Value steht an erster Stelle
• Wenn Kritieren erfüllt => Akzeptiert
Merkmale

• Beschreibung der Features/
  Akzeptanzkriterien in Prosaform
• Automatisiertes ausführen der Features
• Unterstützung von mehreren Sprachen
• Nicht nur für Rails (Java, .Net, Erlang, ... )
Features
Aufbau von Features


•   Titel & Kurzbeschreibung
•   Ein oder mehrere Szenarien (die die
    Akzeptanzkriterien darstellen)
Titel und
Kurzbeschreibung
Feature: Booking
  As a Customer
  I want to book a travel
  So that I can spend my holidays with Sales-Lentz

Scenario:....
Feature: Booking
  As a .... (Role)
  I want to .... (Action)
  So that ... (Buisniss value/ Outcome)
Szenarien
Scenario: booking a Travel
  Given a travel “Rhein in Flammen” for 137.40
  When I go to the detail page of Rhein in Flammen
  When I follow "buchen"
  When I select "Herr" from "Anrede"
  When I fill in "Nachname" with "Mustermann"
  When I fill in "E-Mail" with "hans@mustermann.de"
  When I check "Versicherung"
  When I press "buchen"
  Then I should see "Ihre Buchung"
  Then I should see "Herr"
  Then I should see "Mustermann"
  Then I should see "hans@mustermann.de"
  Then I should see "137,40 EUR"
  Then I should not see "Ausgebucht"
Scenario: booking a Travel
  Given a travel “Rhein in Flammen” for 137.40
  When I go to the detail page of Rhein in Flammen
  And I follow "buchen"
  And I select "Herr" from "Anrede"
  And I fill in "Nachname" with "Mustermann"
  And I fill in "E-Mail" with "hans@mustermann.de"
  And I check "Versicherung"
  And I press "buchen"
  Then I should see "Ihre Buchung"
  And I should see "Herr"
  And I should see "Mustermann"
  And I should see "hans@mustermann.de"
  And I should see "137,40 EUR"
  But I should not see "Ausgebucht"
Aufbau eines Szenarios

• Titel (Scenario:)
• Steps
 • Vorbedingungen (Given)
 • Aktionen (When)
 • Erwartungen (Then)
Features auf Deutsch
Feature: Administrationsbereich
 Als ein angemeldeter Administrator
 Möchte ich die Admin-Seiten besuchen
 So dass ich die Seiten leicht aktualisieren kann.

Szenario: Zugang für Admin-Seite beschränken
  Gegeben sei ein Admin-User
  Wenn ich nicht eingelogged bin
  Und ich die Admin-Seite besuche
  Dann sollte mir der Zugang verweigert werden

Szenario: Zugang für für autorisierten User
 Gegeben sei ein Admin-User
 Und ich bin eingelogged als Admin-User
 Wenn ich die Admin-Seite besuche
 Dann sollte ich "Admin-Bereich" sehen
Automatisieren von
    Features
Ziel

Automatisiertes ausführen der Features
          auf der Applikation
      wie in einem Webbrowser
Step-Definition


Ruby Code, der die Steps in den Szenarien
           ausführbar macht
Given-Step mit Definition

Step
Given a travel “Rhein in Flammen” for 137.40



Step-Definition
Given /^a travel "([^"]*)" for ([0-9.]*)$/ do |title, price|
  Travel.create(:title => title, :price => price.to_f)
end
Given Step-Definition


      • Hier werden meist die Daten vorbereitet
      • Implementierung meist mit ActiveRecord
Given /^a travel "([^"]*)" for ([0-9.]*)$/ do |title, price|
  Travel.create(:title => title, :price => price.to_f)
end
When-Step mit Definition

Step
When I press “buchen”



Step-Definition
When /^I press "([^"]*)"$/ do |button|
  click_button(button)
end
When Step-Definition

    • Hier findet die Interaktion statt
    • Simulation des Browsers
    • Implementierung z.B. mit Webrat
When /^I press "([^"]*)"$/ do |button|
  click_button(button)
end
Then-Step mit Definition

Step
Then I should see "Ihre Buchung"



Step-Definition
Then /^I should see "([^"]*)"$/ do |text|
 response.should contain(text)
end
Then Step-Definition


      • Hier wird geprüft, ob eine bestimmte
        Zeichenkette in der Ausgabe vorkommt
      • Implementierung z.B. mit RSpec
Then /^I should see "([^"]*)"$/ do |text|
 response.should contain(text)
end
features/step_definitions/booking_steps.rb
Given /^a travel "([^"]*)" for ([0-9.]*)$/ do |title, price|
 Travel.create(:title => title, :price => price.to_f)
end

When /^I press "([^"]*)"$/ do |button|
 click_button(button)
end

When /^I fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
 fill_in(field, :with => value)
end

Then /^I should see "([^"]*)"$/ do |text|
 response.should contain(text)
end
Techniken zur Step-
      Definition
• Direct Model Access (z.B. mit
  ActiveRecord)
• Simulated Browser (Webrat)
• Automated Browser (Selenium)
• RSpec-Befehle
Webrat
• Simuliert Browser
• DSL zum steuern des Browsers
• Webrat kann auch ohne Cucumber
  eingesetzt werden (z.B. RSpec, Test::Unit,...)
• Schnell
• kein JavaScript
visit home_path

click_link "Sign up"

fill_in "Email", :with => "good@example.com"

select "Free account"

click_button "Register"
Selenium

• Wird im Firefox-Browser ausgeführt
• Führt JavaScript aus
• Langsam
Tabellen, Outlines und
 weitere Helferleins
Tabellen
Ohne Tabellen
Scenario: booking a Travel
  Given a travel “New York” for 2137.40
  And a travel “San Francisco” for 2137.40
  And a travel “Las Vegas” for 1134.40
  And a travel “Dubai” for 3135.40
  And a travel “London” for 637.40
  And a travel “Berlin” for 337.40
  And a travel “Hamburg” for 437.40
  And a travel “München” for 1137.40
  ...
Mit Tabellen
Scenario: booking a Travel
  Given the following travels
    | title          | price     |
    | New York       | 2137.40   |
    | San Francisco | 2137.40    |
    | Las Vegas      | 1134.40   |
    | Dubai          | 3135.40   |
    | London         | 637.40    |
    | Berlin         | 337.40    |
    | Hamburg        | 437.40    |
    | München        | 1137.40   |
Step Definition
Given /^the following travels$/ do |travels|
    Travel.create(travels.hashes)
end

travels.class == Cucumber::Ast::Table
travels.hashes ==
[
    {:title => “New York”, :price => 2137.40},
    {:title => “San Francisco”, :price => 2137.40},
]
Background
Ohne Background
Scenario: booking a Travel
  Given a travel “New York” for 2137.40
  And a travel “San Francisco” for 2137.40
  And a travel “Las Vegas” for 1134.40
  ....
Scenario: booking a Travel for less than 2000
  Given a travel “New York” for 2137.40
  And a travel “San Francisco” for 2137.40
  And a travel “Las Vegas” for 1134.40
  ....
Don’t repeat yourself
Mit Background
Background:
  Given the following travels
    | title          | price   |
    | New York       | 2137.40 |
    | San Francisco | 2137.40 |
    ...
Scenario: booking a Travel
...

Scenario: booking a Travel for less than 2000
...
Step Definition
Given /^the following travels$/ do |travels|
    Travel.create(travels.hashes)
end

travels.class == Cucumber::Ast::Table
travels.hashes ==
[
    {:title => “New York”, :price => 2137.40},
    {:title => “San Francisco”, :price => 2137.40},
]
Scenario Outlines
Ohne Scenario Outline
Scenario: login with correct user/password
  Given a User “hans” with password “geheim”
  When I visit the login-page
  And I fill in “username” with “hans”
  And I fill in “password” with “geheim”
  Then I should see “Login erfolgreich”

Scenario: login with wrong password
  Given a User “hans” with password “geheim”
  When I visit the login-page
  And I fill in “username” with “hans”
  And I fill in “password” with “blub”
  Then I should see “Login fehlgeschlagen”
Don’t repeat yourself
Mit Scenario Outline
Scenario Outline: login
  Given a User “hans” with password “geheim”
  When I visit the login-page
  And I fill in “username” with <username>
  And I fill in “password” with <password>
  Then I should see <response>

Examples:
  | username | password | response             |
  | hans     | geheim   | Login erfolgreich    |
  | hans     | blub     | Login fehlgeschlagen |
Tags
@iteration2
Scenario: booking a Travel
  Given a travel “New York” for 2137.40
  And a travel “San Francisco” for 2137.40
  And a travel “Las Vegas” for 1134.40
  ....
Scenario: booking a Travel for less than 2000
  Given a travel “New York” for 2137.40
  And a travel “San Francisco” for 2137.40
  And a travel “Las Vegas” for 1134.40
  ....
Aufruf

# Alle Szenarien ausführen mit dem Tag “iteration2”
cucumber - - tags iteration2 features/booking.feature


# Alle Szenarien ausführen ohne den Tag “iteration2”
cucumber - - tags ~iteration2 features/booking.feature
Cucumber installieren
 und konfigurieren
Installation
Gems installieren:
[sudo] gem install rspec rspec-rails cucumber webrat

Verzeichnisse und Konfigurationsdateien generieren
 script/generate cucumber
Ausführen von Cucumber
Alle Features ausführen (mit rake)
rake features

Alle Features ausführen (ohne rake)
cucumber features # vorher ggf. rake db:test:prepare

Einzelnes Feature ausführen:
cucumber features/booking.feature

Einzelnes Szenario ausführen:
cucumber features/booking.feature:24
Demo
Links
Sites


• Homepage: http://cukes.info/
• Linksammlung: http://delicious.com/mucki/
  cucumber
Session & Screencasts
• Railscast.com
 • http://railscasts.com/episodes/156-webrat
 • http://railscasts.com/episodes/155-
        beginning-with-cucumber
  • http://railscasts.com/episodes/159-more-on-
        cucumber
• ...
Literatur
    The RSpec Book:
http://www.pragprog.com
Download der
 Präsentation
  http://devteam.sales-lentz.lu


     Follow us on twitter:
https://twitter.com/HusseinMorsy
   https://twitter.com/ajnato

Einführung in Cucumber mit Rails

  • 1.
    Cucumber Hussein Morsy und Tanja Otto 30.06.2009 Heinrich-Heine-Universität Düsseldorf Rails User Group Düsseldorf
  • 2.
    Über uns • internesEntwicklerteam von Sales-Lentz • IBEs für Reisen, Bustickets, Eventtickets • seit 2006 entwickeln wir mit Ruby on Rails • Buch Ruby on Rails 2 Galileo Press http://www.railsbuch.de
  • 3.
    Wer setzt Cucumberin seinen Projekten ein?
  • 4.
    Aufbau • Philosophie • CucumberFeatures erstellen • Cucumber Features automatisieren • Tabellen, Outlines und weitere Helferleins • Cucumber installieren und konfigurieren • Demo
  • 5.
  • 6.
    Was ist TDD •Hauptmerkmal: Test First • Von Innen nach Aussen • Red => Green => Refactor “Make it green than make it clean” • TDD ist kein Test-Tool, sondern eine Technik für Entwickler
  • 7.
    Units Views Views Views Views Controller Controller Controller Model Model Model Model Model
  • 8.
    TDD-Tools • Unit-Test-Frameworks inRuby • Test::Unit • Shoulda • RSpec • ...
  • 9.
    Ziel von BDD writingsoftware that matters
  • 10.
    Was ist BDD •BDD ist kein Ersatz für TDD • TDD ist ein Bestandteil von BDD • BDD bedeutet outside-in Entwicklung • Wie ein User mit der App arbeiten möchte beeinflusst die Implementierung • Kundenwünsche stehen an erster Stelle
  • 11.
    Outside-In Views Views Views Views Controller Controller Controller Model Model Model Model Model
  • 12.
  • 13.
  • 14.
    Planung • Beschreibung derFeatures bzw. Akzeptanzkritieren • Beschreibung einer Story aus Anwendersicht • Zusammen mit dem Kunden • Business Value steht an erster Stelle • Wenn Kritieren erfüllt => Akzeptiert
  • 15.
    Merkmale • Beschreibung derFeatures/ Akzeptanzkriterien in Prosaform • Automatisiertes ausführen der Features • Unterstützung von mehreren Sprachen • Nicht nur für Rails (Java, .Net, Erlang, ... )
  • 16.
  • 17.
    Aufbau von Features • Titel & Kurzbeschreibung • Ein oder mehrere Szenarien (die die Akzeptanzkriterien darstellen)
  • 18.
  • 19.
    Feature: Booking As a Customer I want to book a travel So that I can spend my holidays with Sales-Lentz Scenario:....
  • 20.
    Feature: Booking As a .... (Role) I want to .... (Action) So that ... (Buisniss value/ Outcome)
  • 21.
  • 22.
    Scenario: booking aTravel Given a travel “Rhein in Flammen” for 137.40 When I go to the detail page of Rhein in Flammen When I follow "buchen" When I select "Herr" from "Anrede" When I fill in "Nachname" with "Mustermann" When I fill in "E-Mail" with "hans@mustermann.de" When I check "Versicherung" When I press "buchen" Then I should see "Ihre Buchung" Then I should see "Herr" Then I should see "Mustermann" Then I should see "hans@mustermann.de" Then I should see "137,40 EUR" Then I should not see "Ausgebucht"
  • 23.
    Scenario: booking aTravel Given a travel “Rhein in Flammen” for 137.40 When I go to the detail page of Rhein in Flammen And I follow "buchen" And I select "Herr" from "Anrede" And I fill in "Nachname" with "Mustermann" And I fill in "E-Mail" with "hans@mustermann.de" And I check "Versicherung" And I press "buchen" Then I should see "Ihre Buchung" And I should see "Herr" And I should see "Mustermann" And I should see "hans@mustermann.de" And I should see "137,40 EUR" But I should not see "Ausgebucht"
  • 24.
    Aufbau eines Szenarios •Titel (Scenario:) • Steps • Vorbedingungen (Given) • Aktionen (When) • Erwartungen (Then)
  • 25.
  • 26.
    Feature: Administrationsbereich Alsein angemeldeter Administrator Möchte ich die Admin-Seiten besuchen So dass ich die Seiten leicht aktualisieren kann. Szenario: Zugang für Admin-Seite beschränken Gegeben sei ein Admin-User Wenn ich nicht eingelogged bin Und ich die Admin-Seite besuche Dann sollte mir der Zugang verweigert werden Szenario: Zugang für für autorisierten User Gegeben sei ein Admin-User Und ich bin eingelogged als Admin-User Wenn ich die Admin-Seite besuche Dann sollte ich "Admin-Bereich" sehen
  • 27.
  • 28.
    Ziel Automatisiertes ausführen derFeatures auf der Applikation wie in einem Webbrowser
  • 29.
    Step-Definition Ruby Code, derdie Steps in den Szenarien ausführbar macht
  • 30.
    Given-Step mit Definition Step Givena travel “Rhein in Flammen” for 137.40 Step-Definition Given /^a travel "([^"]*)" for ([0-9.]*)$/ do |title, price| Travel.create(:title => title, :price => price.to_f) end
  • 31.
    Given Step-Definition • Hier werden meist die Daten vorbereitet • Implementierung meist mit ActiveRecord Given /^a travel "([^"]*)" for ([0-9.]*)$/ do |title, price| Travel.create(:title => title, :price => price.to_f) end
  • 32.
    When-Step mit Definition Step WhenI press “buchen” Step-Definition When /^I press "([^"]*)"$/ do |button| click_button(button) end
  • 33.
    When Step-Definition • Hier findet die Interaktion statt • Simulation des Browsers • Implementierung z.B. mit Webrat When /^I press "([^"]*)"$/ do |button| click_button(button) end
  • 34.
    Then-Step mit Definition Step ThenI should see "Ihre Buchung" Step-Definition Then /^I should see "([^"]*)"$/ do |text| response.should contain(text) end
  • 35.
    Then Step-Definition • Hier wird geprüft, ob eine bestimmte Zeichenkette in der Ausgabe vorkommt • Implementierung z.B. mit RSpec Then /^I should see "([^"]*)"$/ do |text| response.should contain(text) end
  • 36.
    features/step_definitions/booking_steps.rb Given /^a travel"([^"]*)" for ([0-9.]*)$/ do |title, price| Travel.create(:title => title, :price => price.to_f) end When /^I press "([^"]*)"$/ do |button| click_button(button) end When /^I fill in "([^"]*)" with "([^"]*)"$/ do |field, value| fill_in(field, :with => value) end Then /^I should see "([^"]*)"$/ do |text| response.should contain(text) end
  • 37.
    Techniken zur Step- Definition • Direct Model Access (z.B. mit ActiveRecord) • Simulated Browser (Webrat) • Automated Browser (Selenium) • RSpec-Befehle
  • 38.
    Webrat • Simuliert Browser •DSL zum steuern des Browsers • Webrat kann auch ohne Cucumber eingesetzt werden (z.B. RSpec, Test::Unit,...) • Schnell • kein JavaScript
  • 39.
    visit home_path click_link "Signup" fill_in "Email", :with => "good@example.com" select "Free account" click_button "Register"
  • 40.
    Selenium • Wird imFirefox-Browser ausgeführt • Führt JavaScript aus • Langsam
  • 41.
    Tabellen, Outlines und weitere Helferleins
  • 42.
  • 43.
    Ohne Tabellen Scenario: bookinga Travel Given a travel “New York” for 2137.40 And a travel “San Francisco” for 2137.40 And a travel “Las Vegas” for 1134.40 And a travel “Dubai” for 3135.40 And a travel “London” for 637.40 And a travel “Berlin” for 337.40 And a travel “Hamburg” for 437.40 And a travel “München” for 1137.40 ...
  • 44.
    Mit Tabellen Scenario: bookinga Travel Given the following travels | title | price | | New York | 2137.40 | | San Francisco | 2137.40 | | Las Vegas | 1134.40 | | Dubai | 3135.40 | | London | 637.40 | | Berlin | 337.40 | | Hamburg | 437.40 | | München | 1137.40 |
  • 45.
    Step Definition Given /^thefollowing travels$/ do |travels| Travel.create(travels.hashes) end travels.class == Cucumber::Ast::Table travels.hashes == [ {:title => “New York”, :price => 2137.40}, {:title => “San Francisco”, :price => 2137.40}, ]
  • 46.
  • 47.
    Ohne Background Scenario: bookinga Travel Given a travel “New York” for 2137.40 And a travel “San Francisco” for 2137.40 And a travel “Las Vegas” for 1134.40 .... Scenario: booking a Travel for less than 2000 Given a travel “New York” for 2137.40 And a travel “San Francisco” for 2137.40 And a travel “Las Vegas” for 1134.40 ....
  • 48.
  • 49.
    Mit Background Background: Given the following travels | title | price | | New York | 2137.40 | | San Francisco | 2137.40 | ... Scenario: booking a Travel ... Scenario: booking a Travel for less than 2000 ...
  • 50.
    Step Definition Given /^thefollowing travels$/ do |travels| Travel.create(travels.hashes) end travels.class == Cucumber::Ast::Table travels.hashes == [ {:title => “New York”, :price => 2137.40}, {:title => “San Francisco”, :price => 2137.40}, ]
  • 51.
  • 52.
    Ohne Scenario Outline Scenario:login with correct user/password Given a User “hans” with password “geheim” When I visit the login-page And I fill in “username” with “hans” And I fill in “password” with “geheim” Then I should see “Login erfolgreich” Scenario: login with wrong password Given a User “hans” with password “geheim” When I visit the login-page And I fill in “username” with “hans” And I fill in “password” with “blub” Then I should see “Login fehlgeschlagen”
  • 53.
  • 54.
    Mit Scenario Outline ScenarioOutline: login Given a User “hans” with password “geheim” When I visit the login-page And I fill in “username” with <username> And I fill in “password” with <password> Then I should see <response> Examples: | username | password | response | | hans | geheim | Login erfolgreich | | hans | blub | Login fehlgeschlagen |
  • 55.
  • 56.
    @iteration2 Scenario: booking aTravel Given a travel “New York” for 2137.40 And a travel “San Francisco” for 2137.40 And a travel “Las Vegas” for 1134.40 .... Scenario: booking a Travel for less than 2000 Given a travel “New York” for 2137.40 And a travel “San Francisco” for 2137.40 And a travel “Las Vegas” for 1134.40 ....
  • 57.
    Aufruf # Alle Szenarienausführen mit dem Tag “iteration2” cucumber - - tags iteration2 features/booking.feature # Alle Szenarien ausführen ohne den Tag “iteration2” cucumber - - tags ~iteration2 features/booking.feature
  • 58.
  • 59.
    Installation Gems installieren: [sudo] geminstall rspec rspec-rails cucumber webrat Verzeichnisse und Konfigurationsdateien generieren script/generate cucumber
  • 61.
    Ausführen von Cucumber AlleFeatures ausführen (mit rake) rake features Alle Features ausführen (ohne rake) cucumber features # vorher ggf. rake db:test:prepare Einzelnes Feature ausführen: cucumber features/booking.feature Einzelnes Szenario ausführen: cucumber features/booking.feature:24
  • 63.
  • 64.
  • 65.
    Sites • Homepage: http://cukes.info/ •Linksammlung: http://delicious.com/mucki/ cucumber
  • 66.
    Session & Screencasts •Railscast.com • http://railscasts.com/episodes/156-webrat • http://railscasts.com/episodes/155- beginning-with-cucumber • http://railscasts.com/episodes/159-more-on- cucumber • ...
  • 67.
    Literatur The RSpec Book: http://www.pragprog.com
  • 68.
    Download der Präsentation http://devteam.sales-lentz.lu Follow us on twitter: https://twitter.com/HusseinMorsy https://twitter.com/ajnato