Behaviour Driven Development (BDD) - tooltwist/documentation GitHub Wiki

Behaviour Driven Development, or BDD, is a software development process where:

  1. business requirements are written in plain English (or any other language)
  2. these requirements are used to create tests
  3. software is written to pass those tests

The objective is that software is built to meet specific business objectives, and in this way it ties in nicely with Agile development. If you aren't familiar with BDD, I recommend reading Specification by Example - A love story before reading on.

We use a tool named Cucumber, or more specifically cucumber.js, which supports Behaviour Driven Development. A convention named Gherkin is followed, where the use of specific keywords are used to define the business requirements. The objective is to test the various features of the product under development, and this can done by specifying various scenarios that need to be tested for each feature. For example:

Feature: Testing the shopping cart
        In order to take orders
        As an external application calling TEA
        I want to be able to manipulate the shopping cart

        Scenario: Creating a new shopping cart
                Given a clean database
                When I call the web service to create a new shopping cart
                Then the shopping cart should be in the database

        Scenario: Adding to the shopping cart
                Given the shopping cart from the previous scenario
                When I add 2 of product 63 to the shopping cart
                Then the shopping cart should contain 2 of product 63

This Gherkin syntax is supported by various testing tool including the Tool we use, Cucumber. In most cases we use cucumber.js, a Javascript implementation of Cucumber. In these test definitions, the format is always the same: Given... When I... Then... A few other keywords are available (e.g. "And") which are explained here.

Cucumber obviously does not magically understand how to read English and perform the required tests, so how do these plain text descriptions get used? Well, the idea is that once the test have been written, developers then write the test cases to implement those test cases. They do this by writing Steps that pattern match against the descriptions. The following, very cut down example, is written in Javascript, which cucumber.js runs using Node.js. Note that the Given, When, and Then clauses match the test description above.

    ...
    this.Given(/^a clean database$/, function(callback) {

            // Clear existing records from the database
            ...
            callback(); // Pass control back to Cucumber
    });

    this.When(/^I call the web service to create a new shopping cart$/, function(callback) {

            // Call the web service
            ...
            callback();
    });

    this.Then(/^the shopping cart should be in the database$/, function(callback) {

            // Check for the cart the database
            ...
            if (cart_can_not_be_found) {
                    return callback.fail(new Error("Cart not found in REDIS: " + cartId));
            }
            callback();
    });

Links about BDD

Original Cucumber website - http://cukes.info.

Wikipedia - http://en.wikipedia.org/wiki/Behavior_driven_development

A backgrounder for Cucumber - https://github.com/cucumber/cucumber/wiki/Cucumber-Backgrounder.

An example may be of interest, but don't get led astray by the Ruby on Rails: https://github.com/jbpros/cucumber-js-example

http://www.slideshare.net/bmabey/the-why-behind-tddbdd-and-the-how-with-rspec

Cucumber.js

In ToolTwist projects, we set up cucumber.js with the following directory structure:

tests
  |
  +-- features
       +-- shoppingCart.feature
       |
       +-- step_definitions
       |     +-- shoppingCartStepDef.js
       |
       +-- support
            +-- world.js

If you have access, the CloudMall project provides a good example that you may wish to clone as a starting point for other projects.

Links about Cucumber.js

A great guide for getting started with Cucumber.js - http://transitioning.to/2012/01/cucumber-and-js-getting-started-with-cucumber-js/

Website for cucumber.js - https://github.com/cucumber/cucumber-js

So how do you Test?

The steps in a test can do anything, but commonly will do things like:

  • Browser Testing, which drives the application via it's website. At Twist Resources we do this using Selenium ([see here for details](Browser testing using Selenium)).
  • Call code directly. This is possible where the application is written in Javascript, but it's not practical to call Java code from Cucumber.js. In most cases though, code testing is best done using [Unit Testing].
  • Call web services. We do this using a Javascript package named Request. If you have access, the TEA project provides examples of testing web services using Request. See [Testing Web Services] for details.
  • Command Line. Often steps will use command line operations to set up the initial state of tests, such as loading initial data into a database.

Assertions

We use a package named should.js that can be used to test the values of Javascript objects.

user.should.have.property('pets').with.lengthOf(4)

Details of should.js can be found here.

A "Rule of Thumb"

IMPORTANT In most cases, BDD should be used to test from the user's point of view. For example, if you are testing that a webpage correctly adds records to a database, it might seem reasonable to use the web page to add records, and then access the database to confirm that the records are now there. While this works, it is not the best approach for BDD.

A more correct way to check the application is as above - check the application from the user's point of view. In other words, add using the web page (as the user would), and then confirm that the records were added using another web page (as the user would). The important factor is that we are testing the fact that the web pages work to correctly save and retrieve data - the actual method of storage is a separate issue that should probably be tested using unit tests.

Other Useful Links

Getting started with cucumber.js
https://github.com/keithamus/WebCumberNode
https://github.com/meza/webdriver-js-example
http://docs.seleniumhq.org/download/ (Selenium standalone server)
http://net.tutsplus.com/tutorials/javascript-ajax/headless-functional-testing-with-selenium-and-phantomjs/ http://stackoverflow.com/questions/14305806/agile-development-with-javascript

Other testing frameworks

http://pivotal.github.io/jasmine/
https://github.com/searls/jasmine-maven-plugin
http://visionmedia.github.io/mocha/
http://docs.busterjs.org (testing framework with browser testing built in)
http://vowsjs.org
https://github.com/jbpros/cukestall (looks raw)

Other

http://sinonjs.org Chai - assertions
Zombie - headless browser
Soda - Selenium/Node integration
Mocha-cakes - Convert gherkin tests (like cucumber) into tests for Mocha.
ChromeDriver - Chrome adaptor for webdriver (Selenium)