Writing Scenarios¶
Steps¶
Features consist of steps, also known as Givens, Whens and Thens.
Behat doesn’t technically distinguish between these three kind of steps. However, we strongly recommend that you do! These words have been carefully selected for their purpose and you should know what the purpose is to get into the BDD mindset.
Robert C. Martin has written a great post about BDD’s Given-When-Then concept where he thinks of them as a finite state machine.
Givens¶
The purpose of the Given steps is to put the system in a known state before the user (or external system) starts interacting with the system (in the When steps). Avoid talking about user interaction in givens. If you have worked with use cases, givens are your preconditions.
Tip
It’s OK to call into the layer “inside” the UI layer here (in Symfony: talk to the models).
Whens¶
The purpose of When steps is to describe the key action the user performs (or, using Robert C. Martin’s metaphor, the state transition).
Thens¶
The purpose of Then steps is to observe outcomes. The observations should be related to the business value/benefit in your feature description. The observations should inspect the output of the system (a report, user interface, message, command output) and not something deeply buried inside it (that has no business value and is instead part of the implementation).
Caution
While it might be tempting to implement Then steps to just look in the database – resist the temptation. You should only verify output that is observable by the user (or external system). Database data itself is only visible internally to your application, but is then finally exposed by the output of your system in a web browser, on the command-line or an email message.
And & But¶
If you have several Given, When or Then steps you can write:
Scenario: Multiple Givens
Given one thing
Given another thing
Given yet another thing
When I open my eyes
Then I see something
Then I don't see something else
Or you can use And or But steps, allowing your Scenario to read more fluently:
Scenario: Multiple Givens
Given one thing
And another thing
And yet another thing
When I open my eyes
Then I see something
But I don't see something else
Behat interprets steps beginning with And or But exactly the same as all other steps; it doesn’t differentiate between them - you should!
Backgrounds¶
Backgrounds allows you to add some context to all scenarios in a single feature. A Background is like an untitled scenario, containing a number of steps. The difference is when it is run: the background is run before each of your scenarios, but after your BeforeScenario Hooks.
Feature: Multiple site support
Background:
Given a global administrator named "Greg"
And a blog named "Greg's anti-tax rants"
And a customer named "Wilson"
And a blog named "Expensive Therapy" owned by "Wilson"
Scenario: Wilson posts to his own blog
Given I am logged in as Wilson
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
Scenario: Greg posts to a client's blog
Given I am logged in as Greg
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
Scenario Outlines¶
Copying and pasting scenarios to use different values can quickly become tedious and repetitive:
Scenario: Eat 5 out of 12
Given there are 12 cucumbers
When I eat 5 cucumbers
Then I should have 7 cucumbers
Scenario: Eat 5 out of 20
Given there are 20 cucumbers
When I eat 5 cucumbers
Then I should have 15 cucumbers
Scenario Outlines allow us to more concisely express these examples through the use of a template with placeholders:
Scenario Outline: Eating
Given there are <start> cucumbers
When I eat <eat> cucumbers
Then I should have <left> cucumbers
Examples:
| start | eat | left |
| 12 | 5 | 7 |
| 20 | 5 | 15 |
The Scenario Outline steps provide a template which is never directly run. A Scenario Outline is run once for each row in the Examples section beneath it (except for the first header row).
The Scenario Outline uses placeholders, which are contained within < > in the Scenario Outline’s steps. For example:
Given <I'm a placeholder and I'm ok>
Think of a placeholder like a variable. It is replaced with a real value from the Examples: table row, where the text between the placeholder angle brackets matches that of the table column header. The value substituted for the placeholder changes with each subsequent run of the Scenario Outline, until the end of the Examples table is reached.
Tip
You can also use placeholders in Multiline Arguments.
Note
Your step definitions will never have to match the placeholder text itself, but rather the values replacing the placeholder.
So when running the first row of our example:
Scenario Outline: Eating
Given there are <start> cucumbers
When I eat <eat> cucumbers
Then I should have <left> cucumbers
Examples:
| start | eat | left |
| 12 | 5 | 7 |
The scenario that is actually run is:
Scenario: Eating
# <start> replaced with 12:
Given there are 12 cucumbers
# <eat> replaced with 5:
When I eat 5 cucumbers
# <left> replaced with 7:
Then I should have 7 cucumbers
Tables¶
Tables as arguments to steps are handy for specifying a larger data set - usually as input to a Given or as expected output from a Then:
Scenario:
Given the following people exist:
| name | email | phone |
| Aslak | aslak@email.com | 123 |
| Joe | joe@email.com | 234 |
| Bryan | bryan@email.org | 456 |
Attention
Don’t confuse tables with scenario outlines - syntactically they are identical, but they have a different purpose. Outlines declare multiple different values for the same scenario, while tables are used to expect a set of data.
Multiline Arguments¶
The one line steps let Behat extract small strings from your steps and receive them in your step definitions. However, there are times when you want to pass a richer data structure from a step to a step definition.
This is what multiline step arguments are designed for. They are written on lines immediately following a step and are passed to the step definition method as the last argument.
Multiline step arguments come in two flavours: tables or pystrings.
Pystrings¶
Multiline Strings (also known as PyStrings) are useful for specifying a larger piece of text. The text should be offset by delimiters consisting of three double-quote marks ("""), placed on their own line:
Scenario:
Given a blog post named "Random" with:
"""
Some Title, Eh?
===============
Here is the first paragraph of my blog post.
Lorem ipsum dolor sit amet, consectetur adipiscing
elit.
"""
Note
The inspiration for PyString comes from Python where """ is used to delineate docstrings, much in the way /** ... */ is used for multiline docblocks in PHP.
Note
Indentation of the opening """ is not important, although common practice is two spaces in from the enclosing step. The indentation inside the triple quotes, however, is significant. Each line of the string passed to the step definition’s callback will be de-indented according to the opening """. Indentation beyond the column of the opening """ will therefore be preserved.
- Previous chapter
- Initialize a New Behat Project
- Next chapter
- Organizing Features and Scenarios