Wednesday 13 March 2013

BDD with Cucumber

Introduction

Behavioral Driven Development (BDD) in simple terms, allows business owners, developers and testers to collaboratively work together, bound by a "User Story".  User stories are documented in feature files using the gherkin language, along with "scenarios" which when exercised prove that the feature is ready for production.

This blog entry describes a typical setup which can realise the technical aspect of BDD, user stories and automated testing of "scenarios".  Cucumber was originally written in ruby but has been ported to other languages including java.  Here we will look at the Ruby implementation provided by CucumberCapybara and Rspec.


Ruby

Assuming your are working on windows, download a ruby installer from here and install.  Run:

gem install cucumber
gem install rspec
gem install capybara

Make sure that you run these commands from the "Command Prompt with Ruby and Rails".

At this point you should have a workable ruby environment.

IDE

Install the awesome Sublime Text 2.  This will form your gherkin development environment.  Sublime is an excellent editor, blisteringly fast and beautiful.  Start by installing the package manager:
http://wbond.net/sublime_packages/package_control

Using the package manager install:
RubyTest   (https://github.com/maltize/sublime-text-2-ruby-tests)

The following package is not available in the package manager, so needs to be installed by hand.  This provides feature file syntax highlighting:

cd c:/users/<user>/appdata/Roaming/Sublime Text 2/Packages
git clone http://github.com/npverni/cucumber-sublime2-bundle Cucumber

For more packages see http://wbond.net/sublime_packages/community





The following steps can all be done via Sublime without going near the command line.

Setup

Setup the cucumber directory structure:

demo/features
demo/features/step_definitions
demo/features/step_definitions/support


demo/features/search.feature:
 Feature: Search the internet for news
 In order to find news
 As an internet user
 I want to be able to search for news web sites

 Scenario: Search for news providers
 Given I am at http://www.google.co.uk
 And I enter bbc into the search bar
 When I hit search
 Then I will be presented with a list of hits including BBC - Homepage
 When I select the BBC - Homepage link
 Then I will be navigated to website with title BBC - Homepage

This feature file is written in the "Gherkin" language.   This serves as documentation, requirements and test acceptance criteria and  can be written by business owners.  See here for a fuller description of Cucumber.   

Next we will write the step definitions mapping on to each of the "Given ...". "When..." and "Then" in the feature file.

demo/features/step_definitions/step_defs.rb
 Given "I am at $url" do |url|  
      visit url  
 end  
   
 Given "I enter $text into the search bar" do |text|  
      fill_in 'gbqfq', :with => text   
 end  
   
 When "I hit search" do  
      click_button 'gbqfb'  
 end  
   
 Then "I will be presented with a list of hits including $text" do |text|  
      page.should have_content text   
 end       
   
 When "I select the $text link" do |text|  
      click_link text  
 end  
   
 Then "I will be navigated to website with title $title" do |title|  
      page.should have_xpath("//title", :text => title)  
 end  

The visitfill_inclick_button, click_link commands are from the Capybara DSL, and are used to drive a browser, via selenium. page.should  comes from Rspec It's all about driving the web page, then testing for content.  Notice that the step_defs are readable, and very obvious.

demo/features/step_definitions/support/env.rb
 require 'capybara'  
 require 'capybara/cucumber'  
 require 'capybara/rspec'  
   
 Before do  
      Capybara.register_driver :selenium do |app|  
       Capybara::Selenium::Driver.new(app, :browser => :chrome)  
      end  
   
      Capybara.current_driver = :selenium  
 end  

This is the glue which wires everything together and keeps the step_defs clean of clutter:  "Before" is a cucumber hook which runs immediately before the scenario starts executing.  We're using this to configure selenium to use the chrome driver.

Chromium driver

Download the latest Chromium Driver chromium driver and extract into C:/Windows.  Make sure that your chrome browser is up to date.

Testing

Now everything is set up, open a ruby window:
cd demo
cucumber

You should see the chrome browser open up, navigate to www.google.co.uk, enter bbc into the search panel, then navigate over to the bbc website. Here is the cucumber output:


You can also run the cucumber tests via Sublime - select Tools->Ruby Test->Run all Tests/Feature

Notes

I developed this tutorial on a particularly slow internet connection, and I noticed that occasionally, seleniun complained that the browser window was not available (this normally happened on the "Then I will be navigated to website with title BBC - Homepage"  step definition).  I suspect this was a timeout issue.   

I don't like the way selenium dumps output to the command line, interfering with the nicely formatted cucumber output.  There must be a way to stop this?