Behat¶
Behat is a test framework for Behavior Driven Development (BDD) in PHP. BDD is a methodology for developing software through continuous example-based communication between developers and a business.
This communication happens in a form that both the business and developers can clearly understand: examples. The examples are structured around a “Context, Event, Outcome” pattern.
Context, Event, Outcome¶
In Behat, tests are organised into Scenarios, and multiple Scenarios are grouped into Features. Feature files start with the story of the business feature being tested (one per file), followed by at least one Scenario.
Each Scenario consists of a list of Steps, which must start with one of the following keywords: Given
, When
, Then
, But
, And
.
A Scenario always follows the same basic format:
Scenario: Some description of the scenario Given some context When some event Then outcome
Each part of the Scenario – the context, the event, and the
outcome – can be extended by using the And
or But
keywords:
Scenario: Some description of the scenario Given some context And more context When some event And second event occurs Then outcome And another outcome But another outcome
Did you know?
There is no difference between the Then
, And
, and But
keywords. Use each appropriately to write Scenarios that are natural and readable.
Features¶
Imagine that we are building a new e-commerce website. One of the key features of any online shop is the ability to buy products, but before buying anything, customers need to be able to tell the shop which products they want to buy. We need a shopping basket.
With this, we can create our first user story:
Feature: Shopping basket In order to buy products As a customer I need to be able to put interesting products into a basket
Before we start development, we must have a real conversation with our business stakeholders; they might say that they want customers to not only see the combined price of the products in the basket, but also the price reflecting the tax and the delivery cost (which depends on the total price of the products):
Feature: Shopping basket In order to buy products As a customer I need to be able to put interesting products into a basket Rules: - Tax is 20% - Delivery for basket under £10 is £3 - Delivery for basket over £10 is £2
Summary
Features are a simple description of a user story.
The format is always the same: the title of the feature, followed by three lines that describe the benefit, the role, and the feature itself. On subsequent lines, we can add any amount of additional description (such as the rules section, in this example).
In isolation, each rule by itself is understandable, but there is ambiguous complexity when we try to describe the feature in terms of rules. For example, what does it mean to add tax? What happens when we have two products, one of which is less than £10, and another one that is more?
To resolve this, we must have another conversation with our business stakeholders. This will often take the form of actual examples of a customer adding products to the basket. After some back-and-forth, we agree upon a list of behaviour examples.
In BDD, these are called Scenarios.
Scenarios¶
After conversation with our business stakeholders, we came up with the following:
Feature: Shopping basket In order to buy products As a customer I need to be able to put interesting products into a basket Rules: - Tax is 20% - Delivery for basket under £10 is £3 - Delivery for basket over £10 is £2 Scenario: Buying a single product under £10 Given there is a "self-sealing stem bolt", which costs £5 When I add the "self-sealing stem bolt" to the basket Then I should have 1 product in the basket And the overall basket price should be £9 Scenario: Buying a single product over £10 Given there is "yamok sauce", which costs £15 When I add the "yamok sauce" to the basket Then I should have 1 product in the basket And the overall basket price should be £20 Scenario: Buying two products over £10 Given there is "yamok sauce", which costs £10 And there is a "self-sealing stem bolt", which costs £5 When I add the "yamok sauce" to the basket And I add the "self-sealing stem bolt" to the basket Then I should have 2 products in the basket And the overall basket price should be £20
Did you know?
Scenarios in Feature files should focus on the what, rather than the how.
Each Scenario should be concise and to the point, so that the reader can quickly grasp the intent of the test without having to read a lot of irrelevant steps.
The totality of the above represents our business’ shared understanding of our project, written in a structured format. It is based on the clear and constructive conversation we had together with our business stakeholders. This, in essence, is what BDD is.
Contexts¶
Behat allows us to automate behaviour checks by comparing the prescribed behaviour against a system’s actual behavior. Before Behat can do this, we need to teach it how to understand our structured language – otherwise, how is it meant to understand what we mean by “then I should have 2 products in the basket”?
Contexts are PHP objects that tell Behat how to test Features. Behat parses the PHPDoc annotation to map instructions in a Scenario, to methods within Context objects (known as a Step Definition).
Summary
Feature files describe how a system should behave, and Contexts explain how to test it.
A Context always follows the same basic format:
<?php
class FeatureContext implements \Behat\Behat\Context\Context
{
/** @Given some context */
public function prepareContext()
{
// Do something.
}
/** @When some event */
public function doSomeEvent()
{
// Do something.
}
/** @Then outcome */
public function checkOutcome()
{
// Do something.
}
}
The @Given
, @When
, and @Then
keywords allow Behat to match a Step to a method.
In the annotation, Behat can capture tokens (words starting with a colon, e.g.
:arg1
) and pass their value to the method as arguments. Behat also supports optionally matching part of an Step using brackets.
Did you know?
To facilitate more complex matching requirements, Behat supports regular expressions.
An example of a Step Definition required for our e-commerce website is:
<?php
/**
* @Given there is a(n) :arg1, which costs £:arg2
*/
public function thereIsAWhichCosts($arg1, $arg2)
{
// Check $arg1 costs $arg2.
// Add $arg1 to shopping basket.
// If something goes wrong, throw an Exception.
}
The PHPDoc annotation for this method tells Behat that the method should be executed whenever Behat sees a Step that looks like ... there is a ..., which costs £...
. This pattern will match any of the following Steps:
Given there is a "self-sealing stem bolt", which costs £5
Given there is a "self-sealing stem bolt", which costs £10
Given there is an 'automated assembler', which costs £10
Given there is a bolt, which costs £2
Next steps¶
This guide has introduced the basics of Behat and BDD. To learn more, we recommend the following websites and presentations:
- Jessica Mauerhan: “Behat: Beyond the Basic”.
- Knp University: “BDD, Behat, Mink and other Wonderful Things”.
- Inviqa: “The beginner’s guide to BDD”.
- Andy Knight: “The Behavior-Driven Three Amigos”.
You are now ready to begin working with WordHat, but we recommend reviewing our best practices for configuring WordHat for your project.