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 word should 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:
class PHPSpec_Matcher_BeAnInstanceOf extends PHPUnit_Framework_TestCase { public function testShouldPassIfTheObjectNameIsInTheDescription () { $description = $this->matcher->getDescription(); $this->assertSame("be an instance of 'Foo'", $description); } public function testShouldPassIfAMeaningfulFailureMessageIsReturned() { $this->assertSame( "expected 'Foo', got 'Bar' (using beAnInstanceOf())", $this->matcher->getFailureMessage() ); } public function testShouldPassIfAMeaningfulNegativeFailureMessageIsReturned () { $this->assertSame( "expected 'Bar' not to be 'Foo' (using beAnInstanceOf())", $this->matcher->getNegativeFailureMessage() ); } } |
This class lives in BeAnInstanceOfTest.php, and if we run PHPUnit with the --testdox switch:
$ phpunit --testdox BeAnInstanceOfTest.php |
We get a nice report:
PHPSpec_Matcher_BeAnInstanceOf [x] Should pass if the object name is in the description [x] Should pass if a meaningful failure message if returned [x] Should pass if a meaningful failure message if returned |
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
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.
Feature: Member rents video |
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.
Feature: Member rents video As a video-club member I want to rent a video So that I can take it away with me and watch it conveniently at home |
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.
Scenarios
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.
# Content of file renting.feature
Feature: Members rents video
As a video-club member
I want to rent a video
So that I can take it away with me and watch it conveniently at home
Scenario: Renting single video from oldies section
Given I am in the "review" page
And the selected video is "Revolution OS"
When I click on "Rent"
Then "£2" is added to my total
Scenario: Renting 3 videos from oldies promotion
Given I am in the "review" page
And "Revolution OS" is selected
And "Blade Runner" is selected
And "The Wall" is selected
When I click on "Rent"
Then "£5" is added to my total |
Steps
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:
$ sudo pear channel-discover pear.behat.org $ sudo pear channel-discover pear.symfony.com $ sudo pear install behat/gherkin-beta $ sudo pear install behat/behat-beta |
If you have behat 2.0.3 or greater, then you are ready to go.
$ behat --version
Behat version 2.0.3 |
Then navigate to your project root and initialise Behat. This will create the necessary directory structure.
$ cd /path/to/my/project $ ls application docs library public $ behat --init +d features - place your *.feature files here +d features/bootstrap - place bootstrap scripts and static files here +f features/bootstrap/FeatureContext.php - place your feature related code here $ ls application docs features library public |
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:
$ behat |
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:
/** * @Given /^I am in the "([^"]*)" page$/ */ public function iAmInThePage($argument1) { throw new PendingException(); } /** * @Given /^the selected video is "([^"]*)"$/ */ public function theSelectedVideoIs($argument1) { throw new PendingException(); } /** * @When /^I click in "([^"]*)"$/ */ public function iClickIn($argument1) { throw new PendingException(); } /** * @Then /^"([^"]*)" is added to my total$/ */ public function isAddedToMyTotal($argument1) { throw new PendingException(); } /** * @Given /^"([^"]*)" is selected$/ */ public function isSelected($argument1) { throw new PendingException(); } |
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 of Mink, 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:
use BehatBehatExceptionPendingException, BehatMinkBehatContextMinkContext; class RentingFeatureContext extends MinkContext { // steps snippets here... } |
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:
default: context: parameters: start_url: http://renting.local/ class: RentingFeatureContext renting: context: class: RentingFeatureContext |
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:
Scenario: Renting single video from oldies section
Given I am in the "review" page
TODO: write pending definition
And the selected video is "Revolution OS" |
You are now up and running. Start by adding some code in the first Given step:
/** * @Given /^I am in the "([^"]*)" page$/ */ public function iAmInThePage($page) { $this->visit($page); } |
Behat should now be showing green for the first step and point you to the next step:
Scenario: Renting 3 videos from oldies promotion Given I in the "review" page And the selected video is "Revolution OS" TODO: write pending definition And "Blade Runner" is selected |
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).
/** * @Given /^the selected video is "([^"]*)"$/ */ public function theSelectedVideoIs($videoName) { $this->assertPageContainsText($videoName); } |
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.
Scenario: Renting single video from oldies section
Given I am in the "review" page
And the selected video is "Revolution OS"
The text "Revolution OS" was not found anywhere in the text of the current page
When I click in "Rent" |
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.
References
- Chelimsky, David. The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends. The Pragmatic Programmers

18 comments












18 Responses
Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.
Good information about the PHP and its coding which would be useful for the developers.
the problem with
$this->assertPageContainsText($videoName);
is that the video name like others should of course be around the page
i have a similar problem, the problem is that I am loading prices with ajax and i have to use sahi, however not sure if i can default test without javascript and make it to reload with the price updated and then do the assertion, or how to do it...
you did not complete the example, that is sad for me, this is where the true spec bdd and scen bdd came into play! then phpunit spec bdd example would have been very nice! man!
i did some posting also on behat at http://www.craftitonline.com check it out
thanks for the --textdox tip it is amazing and helps one fulfill one of the rules for spec bdd.
Also if this is a wp enable subscribe to comments to promote more interaction.
@cordoval
The video name should be in the page. I am assuming this is a simple synchronous post request, not ajax. If I am doing it with JS I switch to Sahi.
I am glad you liked the agiledox. I noticed you already blogged about it too :) . If you liked this you will love PHPSpec formatters.
You are absolutely right about the example not being complete. This article has a continuation where I dive into spec BDD. Not with PHPUnit though. I will introduce PHPSpec for that part. Watch this channel.
I will talk to the powers about the subscribe thing. Thanks,
Marcello
This seems like it would work as the end-to-end testing in the approach outlined by http://www.growing-object-oriented-software.com/
Unit tests (testing whether a class behaves according to the responsability it is assigned - interface) are still needed though.
Testing whether a class behaves according to the responsibility it is assigned can be done with a Unit Testing framework or a BDD (Spec) Framework.
Another post is coming to cover that.
c'est un bon tutoriel...
Marcello, Thanks for the article, I enjoyed reading it. We use the CodeIgniter MVC Framework where I work, and have been using Behat version 1 to do unit testing based stories. We are able to instantiate a test controller that extends the MVC controller and exercise different code paths within a controller's methods. This may be something like the DMA approach you mention in the article.
Unfortunately I have not been able to get this approach to work with Behat version 2, so I am looking around for other ideas and/or BDD frameworks, and also looking forward to your followup article on the DMA approach to BDD.
Thanks,
Daryl
@Daryl
Can you be more specific about the problems you encountered using Behat 2? And can I recommend that you post your questions to the mailing list: http://groups.google.com/group/behat. I am sure you will get help there. Behat is pretty much the number one tool for BDD acceptance testing in PHP at the moment. Direct Model Access is not a replacement for Behat. In fact you can use DMA with Behat.
HI Marcello, Thank you for your reply. I agree that Behat is the best BDD testing environment that I have seen and used for PHP. I did not mean to imply that DMA was a replacement for Behat, but is perhaps a different way to use Behat. Below is a description of how I have been using Behat and the problem I have run into using Behat version 2. I will also post this to the Behat mailing list, as you suggested.
I have been using Behat version 1 to instantiate and extend a CodeIgniter controller and test different methods in the controller. When I have tried the doing this with Behat version 2, Behat dies with with the php error message:
PHP Fatal error: Call to a member function set_userdata() on a non-object in ...
the mentioned function is a method of the CodeIngniter session class library.
I am trying to instantiate the test controller that extends the CodeIgniter controller in the bootstrap/FeatureContext.php file.
Now the interesting thing is that the object is instantiated and the session method can be accessed before Behat begins running/parsing through the story. I can error_log session variables, etc. but once it starts to print the story the object somehow gets clobbered and it dies with the above error message.
To summarize, my FeatureContext constructor instantiates my test controller, i.e:
public function __construct(array $parameters)
{
// Initialize your context here
$this->controller = new testController();
}
my test controller (which extends the MVC controller) invokes the parent::__construct() method, the session data is printed by the MVC controller, Behat starts to print out "Feature: ...", the MVC prints out empty session data, and then Behat dies with above fatal error.
So it appears that somewhere between when the time the original MVC constructor is called and the time Behat starts to parse the story, the MVC constructor gets clobbered somehow.
Any help, pointers, etc. would be greatly appreciated. I have truly enjoyed working with Behat v1 and really want to get up to speed with your current version.
Thank you, and Best Regards,
Daryl
HI Marcello, Did my explanation not make sense, or is no one else doing this kind of testing, i.e. instantiating a controller object and testing specific methods of the controller? This approach worked really well in Behat v1.
As you suggested, I have also posted the problem to the Behat user group at http://groups.google.com/group/behat but have not heard anything from there either. I guess patience is a virtue.
Best Regards,
Daryl
Hi Daryl,
I am sorry you didn't get a reply at the mailing list. They are usually really good coming back with a reply. To be fair, I haven't had the problem you are describing, since I haven't yet tried Behat with CodeIgniter. Can you create a git repo with just enough code that reproduces your error? I wouldn't mind giving it a go and see if I can understand the problem.
Thanks,
Marcello
Hi Marcello,
Thank you for your reply. I have created a repository on github at:https://github.com/daryl-williams/Behat_CI_Test which may be downloaded with git from git@github.com:daryl-williams/Behat_CI_Test.git.
The repo is as small as I could make it and still reproduce the problem. The CodeIgniter controller just displays a login page and returns a data array that I use to make assertions. There are various debug statements printed with error_log, which Behat displays on stdout, to follow the flow of execution.
The funny thing is that the test passes, but if you try to access or print out the session object Behat prints a fatal PHP error message, so there is no way I can see to initiate a session.
Please let me know if I can provide any further details. I will also post repo to the Behat mailling list and see if it helps.
I am sure you are a busy person, but if you have anytime to look into this, I would greatly appreciate any ideas/thoughts you might have.
Thanks Again,
Daryl
Hello
May Allah reward you
Useful lessons greetings to you all
And you will thank your efforts on the
افضل موقع ربحى عربى
Continuing the Discussion