Getting into Behat with Symfony2

I’ve spent the past week starting a new sprint on our latest large project, and as we’re keen to get our clients as involved as possible during sprints, we decided to get down with some Behaviour-Driven Development (BDD) which allows them to contribute to writing the actual acceptance criteria for the user stories. We’re pretty big on Test-Driven Development here at WO Towers but sometimes it’s necessary to strike a balance between testing every minute detail and no testing. BDD seems to meet that balance whilst providing good code coverage with tests. Note: here I speak of functional tests rather than unit tests.

The beauty of BDD is that it’s written in plain everyday language, and this can be directly translated to code snippets. Therefore the client is happy working “in plain english”, and the developer can crack on with writing the actual code to test these parts.

We’ve chosen to use Symfony2 for the project (more on that in a separate post) and for the BDD aspect we’ve gone with Behat (coupled with Mink); both of which have bundles available for Symfony2. Essentially, BDD boils down to Features, consisting of a number of Scenarios, which in turn consist of a number of Steps. Here’s an example:

Feature: Login to the admin area
	As an administrator 
	I want to be able to log into an admin area
	So I can administer MyApp
	Scenario: Joe Bloggs logs into the admin area
	  Given I visit the admin area
	  When I am shown the login form
	  And I click login with my correct credentials
	  Then I should be on /admin/home

This could translate to code such as the following:

$steps->Given('/^I visit the admin area$/', function($world) {
$steps->When('/^I am shown the login form$/', function($world) {
    $doc = $world->getSession()->getPage();
$steps->And('/^I click login with my correct credentials$/', function($world) {
    $doc = $world->getSession()->getPage();
    $doc->fillField("_username", "joe");
    $doc->fillField("_password", "bloggs");
    $doc->clickButton("Log in");
$steps->Then('/^(?:|I )should be on (?P<page>.+)$/', function($world, $page) {
        parse_url($world->getPathTo($page), PHP_URL_PATH),
        parse_url($world->getSession()->getCurrentUrl(), PHP_URL_PATH)

The beauty of Behat is that the step definitions are reusable, meaning that if you stick to a standard way of describing your steps, the amount of code you need to write is vastly reduced, compared with normal functional TDD. Steps that aren’t implemented yet are given default code as per:

$steps->Given('/^I visit the admin area$/', function($world) {
    throw new \Behat\Behat\Exception\PendingException();

which will translate into the output shown as a step needing to be implemented. Behat also takes note of the Pending exception being thrown and automatically skips any steps following this in the scenario, notifying you of this at the end of the test run.

Behat also comes with a number of standard step definitions built-in, although these are somewhat buried in the code and not in the docs :-( So for example the following steps are part of the included ones:

I go to /my/url:
$steps->When('/^(?:|I )go to (?P<page>.+)$/', function($world, $page) {


I fill in "username" with "foo":
$steps->When('/^(?:|I )fill in "(?P<field>[^"]*)" with "(?P<value>[^"]*)"$/', function($world, $field, $value) {
    $world->getSession()->getPage()->fillField($field, $value);

which translates as even less code to write. Bonus!

Tips ‘n’ tricks

The Mink (browser emulator abstraction layer) setup comes with a Symfony2 driver which is great for just testing normal usage. In our project however we’re integrating Facebook authentication using the FOS FacebookBundle, and we needed a way to test that the user was being bounced to Facebook in order to log in. The solution for this was simple – switch to using Goutte as the driver, as per the BehatBundle docs, and voila, you can test the current URL contains eg or whatever. The actual testing of the authentication itself I’ll write up in a separate blog post as it’s a bit epic for here.

The documentation mentions using a separate front controller for testing, with a separate environment configuration. This is definitely recommended, particularly if you’re using Goutte. If you need services to be available, for example your entity manager, pop something like this in your env.php file:

$kernel = new AppKernel('test', true);
$service = $kernel->getContainer()->get("");

You can also use the env.php file for setting up fixtures that need to be reset for each Scenario that you create, eg pre-defined user states and so on.


Unless you’re using Sahi, you obviously can’t test things such as Javascript popups effectively. I’m in two minds as to whether this should be handled by a new type of Exception which can be thrown e.g. a TestInRealBrowserException(). That way it could be caught and notified to the user running the tests, or flagged as part of an automated build process for manual testing.

Overall, getting into BDD has been a fun and rewarding experience. At times the lack of docs make it somewhat frustrating, but this is easily solved by a) digging into the code and b) probably me getting off my ass and submitting some docs back. The ease of which the steps can be written though is a massive time saver when writing your tests, coupled with the reusability of the code. Big thumbs-up from me!


  1. Posted 15 June 2011 at 8:52 am | Permalink

    The docs are WIP by me and Ryan Weaver ;-)

  2. Posted 15 June 2011 at 9:09 am | Permalink

    Hey guys!

    We’re very glad you like it!
    You’re right about the doc though, this is definitely something we will be working on…


    The KnpLabs team.

  3. Rich
    Posted 15 June 2011 at 12:18 pm | Permalink

    Are the docs open for contributions anywhere? ;-)

  4. Daniel A, Tiecher
    Posted 15 June 2011 at 2:10 pm | Permalink


    You can fork the docs repo ( and submit PR back to upstream when you’re done.

  5. Rich
    Posted 15 June 2011 at 3:52 pm | Permalink

    thanks – missed that repo :-)

  6. Posted 20 June 2011 at 8:54 am | Permalink

    good job guys, this is getting closer to the most clear and proper tutorial that i have read so far, please keep me updated. Also please install the plugin for subscribe to commetns for wp.

    In addition I wonder where are your other posts you talked about. If you get to write them I would love to read them.

2 Trackbacks

  1. […] This was originally posted over at the White October blog but I figured it would fit in nicely here too […]

  2. […] started with Behat for web application testing as well as its own great documentation. For example, and […]

Post a Comment

Your email address is never published nor shared. Required fields are marked *

Ready to talk?

Whether you want to create a new digital product or make an existing one even better, we'd love to talk it through.

Get in touch