BDD with Behat for Symfony2

Behavior Driven Development is an exciting new method of creating software. At LeaseWeb we work with roles like Product Owners, Functional Designers and Testers. These people have no access to the code repository. With BDD (Behavior Driven Development) this might change. BDD allows the Product owner to write the user stories in files with a .feature extension. An example of a feature definition is written below:

Feature: customer_list
  In order to reproduce a customers problem
  As a LeaseWeb employee working in dashboard
  I need to see a list of customers

Scenario: List customers in the dashboard
  Given I am logged in as a employee with username "bob" and password "i<3alice"
  And there is a customer with number "1234567890"
  And there is a customer with number "1234567892"
  When I get redirected after login
  Then I should get a list showing:
    """
    1234567890
    1234567892
    """

As you can see the product owner clarified the user story by describing a scenario. He might add more scenario’s and even backgrounds. Wouldn’t it be really cool if the software developers could implement these scenario’s and the product owner could see the progress by running this file? This is exactly what Behat offers. Software developers implement the methods that Behat generates. By default all generated functions throw a PendingException:

 /**
  * @Given /^I am logged in as a employee with username "([^"]*)" and password "([^"]*)"$/
  */
public function iAmLoggedInAsAEmployeeWithUsernameAndPassword($username, $password)
{
  throw new PendingException();
}

Software developers will replace those throw statements with real implementation like this (this example is using Mink):

 /**
  * @Given /^I am logged in as a employee with username "([^"]*)" and password "([^"]*)"$/
  */
public function iAmLoggedInAsAEmployeeWithUsernameAndPassword($username, $password)
{
  $this->visit('/login');
  $this->fillField('_username', $username);
  $this->fillField('_password', $password);
  $this->pressButton('login');
}

After implementing this function the product owner can run the feature with the “behat” command of Symfony2. The product owner sees the feature where every step of the scenario is colored. Green steps are implemented, brown steps are not yet implemented (Pending) and blue ones are skipped because they depend on pending steps. At the end of the run Behat shows a summary:

1 scenario (1 pending)
5 steps (1 passed, 3 skipped, 1 pending)
0m0.855s

Why BDD might make a huge difference:

  • Stories and scenario’s are added to the repository and can: easily be found, verified and related to a version or release.
  • It enables the product owner to get a visual and understandable view of the progress of the team.
  • The team will write good user stories and scenario’s since they are an important part of the development process.

And in a way it makes user stories and scenario’s “fun” for developers and product owners.

Read more about this topic:

Installation instructions:

Add git repositories to the “deps” file and update vendors afterwards with “bin/vendors install”. If your project is based on a Standard Edition that includes vendors you cloud consider cloning the repositories manually into the target directories.

In the “deps” file add:

...

[BehatBundle]
  git=https://github.com/Behat/BehatBundle.git
  target=/bundles/Behat/BehatBundle

[MinkBundle]
  git=https://github.com/Behat/MinkBundle.git
  target=/bundles/Behat/MinkBundle

You also need to install pear and the required packages.
IMPORTANT: sometimes this process hangs for several minutes, be prepared to have a lot of patience!

$ sudo apt-get install php-pear php5-curl php5-dev
$ sudo pear upgrade pear
$ sudo pear channel-discover components.ez.no
$ sudo pear channel-discover pear.symfony-project.com
$ sudo pear channel-discover pear.phpunit.de
$ sudo pear install --alldeps phpunit/PHPUnit
$ sudo pear channel-discover pear.symfony.com
$ sudo pear channel-discover pear.behat.org
$ sudo pear install --alldeps behat/behat
$ sudo pear install --alldeps behat/mink

In app/AppKernel.php:

public function registerBundles()
{
  ...
  if ($this->getEnvironment() === 'test') {
    $bundles[] = new Behat\BehatBundle\BehatBundle();
    $bundles[] = new Behat\MinkBundle\MinkBundle();
    if (!defined('BEHAT_AUTOLOAD_SF2')) define('BEHAT_AUTOLOAD_SF2', false);
    require_once 'behat/autoload.php';
    require_once 'gherkin/autoload.php';
    require_once 'mink/autoload.php';
  }
  return $bundles;
}

In app/autoload.php:

$loader->registerNamespaces(array(
  ...
  'Behat\\BehatBundle'=>__DIR__.'/../vendor/bundles',
  'Behat\\MinkBundle'=> __DIR__.'/../vendor/bundles',
));
Share

Leave a Reply

Your email address will not be published. Required fields are marked *