Cucumber

Behrang Noruzi Niya

Cucumber

March 12, 2013

Cucumber

Cucumber is a Behavior-Driven Development tool.

What is BDD?

BDD History

Developed by Dan North

Dan North, Agile Troublemaker, Developer, Originator of BDD

BDD History

As a response to TDD issues:

Behavioral Specifications

  1. Unit tests should be specified in terms of the desired behavior (business requirement).
  2. Behavior should be specified in terms of user storeis.

User Story Structure

			Story: Returns go to stock

			In order to keep track of stock
			As a store owner
			I want to add items back to stock when they're returned

			Scenario 1: Refunded items should be returned to stock
			Given a customer previously bought a black sweater from me
			And I currently have three black sweaters left in stock
			When he returns the sweater for a refund
			Then I should have four black sweaters in stock

			Scenario 2: Replaced items should be returned to stock
			Given that a customer buys a blue garment
			And I have two blue garments in stock
			And three black garments in stock.
			When he returns the garment for a replacement in black,
			Then I should have three blue garments in stock
			And two black garments in stock

Tests

TDD tools: free-format

BDD tools: linked to ubiquitous language

BDD Tools

They make same requirements documents executable.

Back to Cucumber

Cucumber

Developed by Aslak Hellesøy originally for Ruby

Aslak Hellesøy

Cucumber Implementations

cucumber.js

Developed by Julien Biezemans

Aslak Hellesøy

Install cucumber.js

			npm install cucumber -g

Gherkin

Gherkin

User stories should be written in gherkin format.

Gherkin Sample

			Feature: Google for Cucumber
			  In order to get more info about Cucumber
			  As a BDDer
			  I want to find Cucumber resources on Google

			  Scenario: find cukes.info
			    Given I am on Google
			    When I search for "Cucumber BDD"
			    Then I see a link to "http://cukes.info/"

Paste in features/google.feature

			$ cucumber.js
			UUU

			1 scenario (1 undefined)
			3 steps (3 undefined)

			You can implement step definitions for undefined steps with these snippets:

			this.Given(/^I am on Google$/, function(callback) {
			  // express the regexp above with the code you wish you had
			  callback.pending();
			});

			this.When(/^I search for "([^"]*)"$/, function(arg1, callback) {
			  // express the regexp above with the code you wish you had
			  callback.pending();
			});

			...

Step Definition

Glue between features written in Gherkin and the actual SUT.

			module.exports = function () {

			  this.Given(/^I am on Google$/, function(callback) {
			    // express the regexp above with the code you wish you had
			    callback.pending();
			  });

			};

Paste in features/step_definitions/google.js

			$ cucumber.js
			PUU

			1 scenario (1 undefined)
			3 steps (2 undefined, 1 pending)

			You can implement step definitions for undefined steps with these snippets:

			this.When(/^I search for "([^"]*)"$/, function(arg1, callback) {
			  // express the regexp above with the code you wish you had
			  callback.pending();
			});

			this.Then(/^I see a link to "([^"]*)"$/, function(arg1, callback) {
			  // express the regexp above with the code you wish you had
			  callback.pending();
			});
			module.exports = function () {

			  this.Given(/^I am on Google$/, function(callback) {
			    // express the regexp above with the code you wish you had
			    callback.pending();
			  });

			  this.When(/^I search for "([^"]*)"$/, function(arg1, callback) {
			    // express the regexp above with the code you wish you had
			    callback.pending();
			  });

			  this.Then(/^I see a link to "([^"]*)"$/, function(arg1, callback) {
			    // express the regexp above with the code you wish you had
			    callback.pending();
			  });

			};

Pending For Implementation

			$ cucumber.js
			P--

			1 scenario (1 pending)
			3 steps (1 pending, 2 skipped)

Browser Simulator

"Given I am on Google" needs a browser! Or a browser simulator!

Some of the more popular choices:

PhantomJS

Install manually, or use npm:

			npm install phantomjs -g

Then run PhantomJS with:

			phantomjs --webdriver=4444

WebDriver

			npm install wd --save-dev

Given I am on Google

			module.exports = function () {

			  var browser;

			  this.Given(/^I am on Google$/, function(callback) {
			    browser = require('wd').remote();
			    browser.on('status', console.log);
			    browser.on('command', console.log);
			    browser.init(function () {
			      browser.get('http://google.com', callback);
			    });
			  });

			  ...

Given I am on Google, Passes!

			$ cucumber.js

			Driving the web on session: a4168050-8a24-11e2-81f1-e98c10564ba0

			POST /session/:sessionID/url { url: 'http://google.com' }
			.P-

			1 scenario (1 pending)
			3 steps (1 pending, 1 skipped, 1 passed)

Improve Readability

Replace RegExp:

		  this.Given(/^I am on Google$/, function(callback) {

With simple string:

		  this.Given('I am on Google', function(callback) {

When I search for "Cucumber BDD"

		  this.When('I search for "$query"', function(query, callback) {
		    browser.elementByName('q', function (err, el) {
		      el.type(query + '\n', callback);
		    });
		  });

Second Step Passes

			$ cucumber.js -f pretty
			Feature: Google for Cucumber
			  Scenario: find cukes.info

			Driving the web on session: c2c11e90-8a27-11e2-81f1-e98c10564ba0

			POST /session/:sessionID/url { url: 'http://google.com' }
			    Given I am on Google
			POST /session/:sessionID/element { using: 'name', value: 'q' }
			POST /session/:sessionID/element/:wdc:1362991417552/value { value: [ 'Cucumber BDD\n' ] }
			    When I search for "Cucumber BDD"
			    Then I see a link to "http://cukes.info/"

			1 scenario (1 pending)
			3 steps (1 pending, 2 passed)

Then I see a link to "http://cukes.info/"

	    this.Then('I see a link to "$url"', function(url, callback) {
		    browser.waitForElementByCss(
		    		'a[href*="' + url + '"]', 5000, function (err, el) {
		      if (err) {
		        callback.fail();
		      } else {
		        browser.quit();
		        callback();
		      }
		    });
		  });

Scenario Passes

			$ cucumber.js

			Driving the web on session: bcb35250-8a33-11e2-81f1-e98c10564ba0

			POST /session/:sessionID/url { url: 'http://google.com' }
			.POST /session/:sessionID/element { using: 'name', value: 'q' }
			POST /session/:sessionID/element/:wdc:1362996561183/value { value: [ 'Cucumber BDD\n' ] }
			.POST /session/:sessionID/elements { using: 'css selector',
			  value: 'a[href*="http://cukes.info/"]' }
			POST /session/:sessionID/elements { using: 'css selector',
			  value: 'a[href*="http://cukes.info/"]' }
			DELETE /session/:sessionID undefined
			.

			1 scenario (1 passed)
			3 steps (3 passed)
		  module.exports = function () {
			  var browser;
			  this.Given('I am on Google', function(callback) {
			    browser = require('wd').remote();
			    browser.init(function () {
			      browser.get('http://google.com', callback);
			    });
			  });
			  this.When('I search for "$query"', function(query, callback) {
			    browser.elementByName('q', function (err, el) {
			      el.type(query + '\n', callback);
			    });
			  });
			  this.Then('I see a link to "$url"', function(url, callback) {
			    browser.waitForElementByCss('a[href*="' + url + '"]', 5000, function (err, el) {
			      if (err) {callback.fail();} else {browser.quit();callback();}
			    });
			  });
			};

Green like a cuke!

			$ cucumber.js -f pretty

			Feature: Google for Cucumber
			  In order to get more info about Cucumber
			  As a BDDer
			  I want to find Cucumber resources on Google


			  Scenario: find cukes.info                   # features/google.feature:6
			    Given I am on Google                      # features/google.feature:7
			    When I search for "Cucumber BDD"          # features/google.feature:8
			    Then I see a link to "http://cukes.info/" # features/google.feature:9

			1 scenario (1 passed)
			3 steps (3 passed)

World

Constructor function with utility properties, used in step definitions.

Value of this in step definitions.

Hooks

Gherkin Example 1

			Feature: Google for Cucumber
			  In order to get more info about Cucumber
			  As a BDDer
			  I want to find Cucumber resources on Google

			  Scenario: find cukes.info
			    Given I am on Google
			    When I search for "Cucumber BDD"
			    Then I see a link to "http://cukes.info/"

Gherkin Example 2

			Feature: Search courses
			  In order to ensure better utilization of courses
			  Potential students should be able to search for courses

			  Scenario: Search by topic
			    Given there are 240 courses which do not have
			      the topic "biology"
			    And there are 2 courses A001, B205 that each
			      have "biology" as one of the topics
			    When I search for "biology"
			    Then I should see the following courses:
			      | Course code |
			      | A001        |
			      | B205        |

Declarative vs. Imperative

The scenarios are ideally phrased declaratively rather than imperatively - in the business language, with no reference to elements of the UI through which the interactions take place.

Bad Example, Login

			Scenario: Successful login
			  Given a user "Aslak" with password "xyz"
			  And I am on the login page
			  And I fill in "User name" with "Aslak"
			  And I fill in "Password" with "xyz"
			  When I press "Log in"
			  Then I should see "Welcome, Aslak"

Bad Example, Login Before Each Scenario

			Background: A logged in user
			  Given a user "Aslak" with password "xyz"
			  And I am on the login page
			  And I fill in "User name" with "Aslak"
			  And I fill in "Password" with "xyz"
			  When I press "Log in"
			  Then I should see "Welcome, Aslak"

Login Example

			Scenario: User is greeted upon login
			  Given the user "Aslak" has an account
			  When he logs in
			  Then he should see "Welcome, Aslak"

Login Example, For Each Scenario

			Background: The user is logged in
			  Given a logged in user

			Scenario: Upload a picture
			  # Some steps here

Cucumber & Documentation

Cucumber features are living documentation

Integration and Acceptance Tests

Cucumber is better used for end to end (integration or system) testing.

Use cucumber for acceptance tests of user stories.

Don't use for unit tests.

BDD Tools For Unit Test

Agile Process

I18N

			ویژگی: جستجوی خیار در گوگل
			  برای این که بیشتر درباره خیار بدانم
			  به عنوان یک کاربر BDD
			  میخواهم که در گوگل منابع خیار را پیدا کنم
			 
			  سناریو: جستجوی cukes.info
			    با فرض من در گوگل هستم
			    هنگامی من "Cucumber BDD" را جستجو میکنم
			    آنگاه من یک پیوند به "http://cukes.info" میبینم
		

Books

The Cucumber Book Cucumber Recipes

References

Shower: github.com/shower/shower

Cucumber Cucumber Logo

Behrang Noruzi Niya

Questions?