BDD Javascript Ontwikkelen met Cucumber

4 May 2010 9:04 Iain Hecker Javascript, Ruby, Testen

Het is weer komkommertijd. Ruim een jaar geleden schreef ik een blogpost over de testtool “Cucumber“. Cucumber is een testtool om in BDD-stijl te ontwikkelen. Afgelopen zondag kwam versie 0.7.1 uit, dus is het nu een goed moment om er weer eens naar te kijken. Dit keer nemen we onder de loep hoe je met Cucumber de browser in kan zetten om integratietests te doen. Aan het eind kan je zelfs in een filmpje zien wat het resultaat is.

Waarom?

Normaliter zal Cucumber geen browser gebruiken, maar direct aan de server de html opvragen. Dit is redelijk snel en voor de meeste gevallen meer dan zat. Maar wat als er javascript op de pagina zit? In eerste instantie kan je je website volledig degradable maken, zodat het ook werkt voor mensen zonder javascript. Daar zijn twee problemen mee. Ten eerste is dat niet altijd mogelijk. Sommige zaken zijn nou eenmaal niet degradable te maken. Ten tweede test je daarbij de javascript niet.

Er zijn verschillende oplossingen om javascript te testen. Je kan JSUnit of ScrewUnit gebruiken om javascript unit tests te schrijven, of je kan met Selenium testsscripts in elkaar zetten. Dit werkt echter alleen nadat de functionaliteit al bestaat. Je hebt voor Ruby ook een gem genaamd ‘Johnson‘, die SpiderMonkey, de javascript engine van Firefox, direct kan aanspreken.

Het liefst ontwikkelen we BDD. Tools als ScrewUnit en Johnson maken dat mogelijk op unit test niveau. Cucumber is anders, want daarmee kun je op integratie niveau testen. Cucumber wordt tegenwoordig onder water aangestuurd door Capybara. Capybara biedt een prettige API aan om verschillende testmechanismen aan te roepen, zoals Culerity, Watir en Selenium. Het past ook als gegoten in Cucumber.

Installatie

We beginnen met een Rails applicatie. Installeer Rails 3 en maak je applicatie. Rails 3 is nog in beta fase, maar stabiel genoeg om al mee te werken.

gem install rails --pre
rails naam_van_applicatie
cd naam_van_applicatie/

Rails 3 werkt samen met Bundler: een gem dependency manager. Om de dependencies toe te voegen, openen we de Gemfile en voegen de group :test toe.

group :test do
  gem 'test-unit', :require => 'test/unit'
  gem 'rspec-rails', '2.0.0.beta.8'
  gem 'capybara'
  gem 'database_cleaner'
  gem 'cucumber-rails', :git => "git://github.com/aslakhellesoy/cucumber-rails.git"
  gem 'launchy'
end

We gebruiken een versie van Cucumber-Rails die direct van Github af komt, vanwege een kleine bugfix die al klaar staat, maar nog niet officieel gereleased is.

Installeer de dependencies, zet de database op en genereer de files voor cucumber:

bundle install
rake db:setup
rails generate cucumber:skeleton --rspec --capybara

We zijn nu klaar om integratietests te schrijven.

Onze eerste feature

Dit voorbeeld is gebaseerd op de tafelvoetbal competitie applicatie. Deze features zijn in het Engels en dat is handig want er staan al veel Engelstalige stappen gedefinieerd. Zouden we dat in het Nederlands doen, dan moeten we deze stappen eerst nog vertalen.

We zeggen tegen cucumber dat voor deze feature de javascript modus gebruikt moet worden door te beginnen met @javascript. Standaard wordt dat gedraaid met Selenium. Daarna schrijven we de cucumber feature zoals we dat normaliter zouden doen:

@javascript
Feature: Manage players
 
  In order to register matches played
  as a user
  I want to manage players
 
  Scenario: Register new player
    Given I am on the new player page
    When I fill in "Name of the player" with "Bob"
    And I press "Save!"
    Then I should see "Bob"
    And I should see "The player was saved"

We slaan dit op in features/manage_players.feature en draaien de cucumber task:

rake cucumber

Dit faalt natuurlijk. We hebben nog helemaal niks gemaakt, enkel het gedrag gespecificeerd. We kunnen nu gaan programmeren tot we het gewenste gedrag hebben bereikt. Dit is Behavior Driven Development. Je zal zien dat Cucumber je helpt met het implementeren van de features door handige foutmeldingen te geven. De eerste foutmelding ziet er zo uit:

Screen shot 2010-05-03 at 17.27.44

Resultaat

Het schrijven van de daadwerkelijke code valt buiten de scope van deze post.

Tijdens het programmeren draaien we regelmatig de testsuite. Naarmate we meer implementeren zullen steeds meer falende tests veranderen in slagende tests. Tevens garandeer je de werking van de applicatie gedurende de ontwikkeling.

Het resultaat heb ik gefilmd en kan je hier bekijken. Door middel van de configuratie aan te passen draaien deze tests ook onder Chrome en Internet Explorer (alhoewel ik Internet Explorer nog niet uitgeprobeerd heb).

Je kan Cucumber ook gebruiken voor het testen van console applicaties en voor webapplicaties die niet met Ruby gemaakt zijn. Kijk voor meer informatie op de website van Cucumber.

Wil je de complete code zien van de applicatie, ga dan naar Github.

3 reacties »

  1. [...] This post was mentioned on Twitter by Ariejan, Ariejan, Iain, Rotterdam.rb, Finalist IT Group and others. Finalist IT Group said: new blogpost: BDD Javascript Ontwikkelen met Cucumber http://bit.ly/bthdAN #javascript #ruby [...]

    Tweets that mention BDD Javascript Ontwikkelen met Cucumber | Finalist Developers Blog -- Topsy.com May 4, 2010 10:35

  2. Ja, cucumber-rails 0.3.1 is uit, je hoeft dus in je Gemfile niet meer direct te verwijzen naar de git-repo.

    source "http://rubygems.org"
    gem 'rails', '3.0.0.beta3'
    gem 'sqlite3-ruby', :require => 'sqlite'
     
    # meer dependencies hier
     
    group :test do
      gem 'test-unit', :require => 'test/unit'
      gem 'rspec-rails', '2.0.0.beta.8'
      gem 'capybara'
      gem 'database_cleaner'
      gem 'cucumber-rails'
      gem 'launchy'
    end

    Iain Hecker May 4, 2010 19:30

  3. [...] schrijf je voor het huidige gedrag integratietests, met bijvoorbeeld Cucumber, om het huidige gedrag vast te leggen. Dit zorgt ervoor dat je zonder problemen kan gaan hakken in [...]

    RailsConf 2010, Tutorials: Avoiding and Fixing Rails Antipatterns | Finalist Developers Blog June 8, 2010 8:08

Reageer

RSS feed for comments on this post · TrackBack URI