Back to blog home

Behaviour driven development in PHP with Behat

Outside-in Development is an agile development methodology that places the intention and goals of the stakeholders at the centre of the process. This is achieved by having human-readable user stories and scenarios being invoked as scripts that feed back on the progress, continuously leading the development towards the stakeholders’ goal. Developers will start from this executable specification, and write the high level controllers that will provide the functionality. They then go into what they need to provide that functionality by specifying how their library class should work. By the time all classes’ specifications are met, all scenarios will also be fulfilled and the cycle is complete.

The evolution from TDD to BDD

The idea of using the specification to drive the development is an evolution from Test-Driven Development, or TDD. TDD is the practice of writing a test before writing the code to be tested. This is an iterative process; you'd start with red (failing test), write just only enough code to make the result turn green (passing test), then remove or re-organise the code, without causing the test to fail, and start again. As the codebase grows, refactoring becomes the core of the process. TDD plays an important role in allowing the refactoring to happen, allowing good quality code to be passed on to QA.

BDD (Behaviour-Driven Development) emerged from Dan North's attempt to teach TDD. His pupils would often ask the same questions, and if you've been to talks about testing then you have probably heard these questions yourself:

What should I test? How should I name this test? What is a unit? Where do I start?

Dan concluded that a big part of the problem was the word test.

Because of the emphasis on test, developers tend to focus on class structure as opposed to how the system should behave. Ironically the focus on test moves developers away from TDD as it was intended. Quite often, because of the tendency to try to test everything, our tests end up tightly coupled with our implementation. If we change our code, we break our tests, even if the behaviour remains unchanged.

A few words on words

If you run PHPUnit with the -- testdox switch, you'll see that the tests' names are printed in a human-readable form. This feature is inspired by a tool called agiledox developed by Chris Stevenson. In using this tool, Dan realised that he could name his tests in an expressive way, letting others know what he was testing. He started using the wordshould in the test name, and stopped calling it a test, replacing it by behaviour. Here is an example PHPUnit test case that uses should in the test name:

This class lives in BeAnInstanceOfTest.php, and if we run PHPUnit with the --testdox switch:

We get a nice report:

After this realisation, Dan North started writing a replacement for JUnit, called JBehave. JBehave introduced another important shift in vocabulary, reducing the traditional Four-Phase test process (setup, exercise, verify and teardown) pattern into three: Given/When/Then.

Software development is all about communication, and this pattern is more sensible for business analysts, testers and developers alike. Specifying behaviour in a common language means stakeholders can take part in the process by identifying and expressing the scenarios.

The Gherkin language

Gherkin is the language and parser that was created to specify features, as a part of a BDD tool called Cucumber. The language defines the structure of a feature, setting a number of keywords that can be used to describe the feature. The structure contains:

  • A title
  • A story
  • Scenarios
  • Steps


A Title
We start by specifying a title. The title of the feature should describe the activity done by a stakeholder in the system. If we were building a software to manage a video club, we might have a feature to record the renting by the members.

Note that we chose the title "Member rents video". This indicate that without this feature a member cannot rent any video from the collection. It should not be a topic, or a theme, but an activity performed in the system. A vague, less descriptive name would be "Renting Management" or "Video renting feature". The title should make it explicit what functionality will be implemented.

A Story
The next thing is the user story (you can read an earlier techPortal article about user stories for more information). A story has 3 components to it: an actor, a behaviour and a reason, which outlines the value it brings to the stakeholders.

Requiring a "so that" clause not only forces the team to think about the reasons for needing this feature, but it also makes it clear that the feature is enough to deliver what we expect from this story.

Each scenario has a title and a series of steps. The title should distinguish the scenario from all others. By reading the title you should be able to quickly guess how this scenario is different from all others. The steps are a series of pre-conditions, events and results, defined using one or more Given/When/Then clauses.

Steps are the building blocks of scenarios where each of the blocks is a requirement. Given/When/Then steps are intentionally flexible and adaptable. They are there to support the communication between the business and development teams. As the conversation evolves and the understanding of the feature changes we can easily update them. Use Given to state pre-conditions or context; When to describe the interaction with the system and Then is there to describe the expected outcome. You can also use And to combine more conditions, interactions or outcomes, e.g. Given some condition And some other condition When I do something And I do something else Then I obtain this outcome And This also happens

Introducing Behat, putting Gherkin to use in PHP

Once you have written your scenarios using Gherkin, you can automate these using a tool such as Behat. Behat is a tool inspired by Cucumber, and written in PHP by Konstantin Kudryashov. At the time of writing, Behat 2.0.3 has been released and the syntax for this version is used in the examples for this article.

First you need to get Behat installed on your system. It is available from PEAR and you can install it by doing the following:

If you have behat 2.0.3 or greater, then you are ready to go.

Then navigate to your project root and initialise Behat. This will create the necessary directory structure.

Time to start adding features. Under the features directory create a new file and name it renting.feature and add the content of "Feature: Member rents video" to the file and save it. At this point, we can let Behat tell you what to do next:

Running this command will result in Behat outputting the code you have to write in PHP for defining your steps, with a message saying "You can implement step definitions for undefined steps with these snippets:". Note that the names of the methods are based on the text in the Given/When/Then from the scenario steps created above:

Step definition styles

Now that Behat has generously provided the skeleton of your steps, you can add the code into it. The code should contain examples of how the system should behave. The beauty of Behat is that you can easily model the interaction with the user by using methods like visit($page), pressButton($button), clickLink($link). This is possible because ofMink, a layer on top of Behat that simulates the user interaction with the browser.

For newcomers to tools like Behat or Cucumber, their early questions tend to be:

what do I put in the steps? Should I connect to the database via hooks to populate the DB? Should I simulate the user interaction including previous steps to add some data?

David Chelimsky[1] identified three different approaches, or step definition styles, of what to put in the step definitions: Automated Browser, Simulated Browser or DMA (Direct Model Access). The first two styles can be accomplished in Behat by using Mink with a driver; either Sahi for the Automated Browser approach or Goutte for Simulated Browser. DMA can be achieved by accessing the models directly from the step definition to add or retrieve some data to or from the database.

I am going to use Mink with the default driver, Goutte, however if your pages have Javascript you should use the Sahi driver.

First lets create a RentingFeatureClass which will look like this:

There is just one more step to complete the setup. You need to add a behat.yml to add your context. By default, Behat sets FeatureContext.php as the default context and if you add your steps to that file instead, Behat would be running those. However since you want to add more and more features in separate files, this isn't the best approach. You can add subcontexts to the main feature context, however for the sake of simplify let's just tell Behat to run our context alone. Also we need to tell Mink where the base URL for our application is. Therefore in the root of your project directory, create a behat.yml with the following code:

If you run Behat again you should get

2 scenarios (2 pending) 10 steps (8 skipped, 2 pending

Instead of: 2 scenarios (2 undefined) 10 steps (10 undefined)

Behat is now pointing to the first step:

You are now up and running. Start by adding some code in the first Given step:

Behat should now be showing green for the first step and point you to the next step:

At this point we can add a bit more context. The user has already selected some videos. Mink will use a PHPUnit assertion for this. In fact, you can use virtually any assertion family; SimpleTest would work just as well (Lime is not ideal however, because it doesn't throw exceptions).

Great! Now we got our first failure. This might not seem like great news, but as we originally stated, it is the first step in the process.

Once you get a failure in Behat, it is time to go deeper and at this point the true outside-in begins. So far we have used Behat to specify how our application would interact with the user. Now it's time to go to our classes and specify how they will work with each other.

This article introduced the idea of BDD and also showed how we can set up scenarios to describe our application and execute these with Behat. Keep watching techPortal for the follow-up article, which will cover how to specify class behaviour with PHPSpec.