Behaviour Driven Development, or BDD, is a valuable collaboration technique for bridging the gap between developers and wider stakeholders. One part of BDD is the tools or frameworks that can be used to convert BDD statements into actual running tests. This post goes through a simple example using the pytest-bdd plugin.
Python BDD with pytest-bdd
There are different ways of implementing BDD in python and I have chosen to focus on pytest-bdd, a plugin for the popular pytest test framework. For a more comprehensive run-down of different Python BDD frameworks you could use I suggest reading this excellent blog post.
For these examples I am going to use a simple example of a python ‘Greeter’ class which says hello. This example is available on GitHub if you just want to get stuck in.
The Gherkin Language
A big part of BDD is using the Gherkin language as a way of specifying expected behaviour in plain language. Here’s an example.
As a user
I want to be greeted nicely
So that I feel welcomed.
Scenario: No name provided
Given a Greeter
When I don’t provide a name
Then the greeter says "Please provide a name"
Let’s break this example down. The first line specifies the name of the feature being described, below which is a ‘user story’ style declaration of what the user expects of the feature.
The scenario is one aspect of this feature that we want to specify. In this case we want to specify what should happen when a name isn’t provided.
At this stage we deliberately haven’t said anything about any implementation details. The ‘given’, ‘when’, ‘then’ language corresponds to the concepts of ‘set up’ -> ‘run code’ -> ‘assert outcome’. This linguistic link between the world of the developer and customer or stakeholder is a key part of what makes BDD useful.
Linking Gherkin With Python
I am using the pytest-bdd framework (it’s a plugin to pytest). By convention feature files are stored in a ‘features’ directory. The feature files contain the Gherkin that specify the expected behaviour.
To actually run the Gherkin as python tests we need to create some ‘step definitions’. By convention these step definitions are created in a folder named ‘step_defs’.
pytest-bdd is a pytest plugin, and we ‘drive’ it by having it pick up test scripts in the same way that pytest does.
src/ L package_name L package.py tests/ L features L feature_file.feature L step_defs L test_feature.py
There are a few things we need to make sure our ‘step_def’ file has before we can get to actually implementing the tests.
Firstly the imports. Secondly, we need to specify where pytest-bdd can find the corresponding feature file for this step_def file.
from pytest_bdd import given, when, then, scenarios scenarios('../features)
With these pre-requisites in place we can actually implement the tests. The link to the ‘given’, ‘when’, ‘then’ in the feature file is achieved with decorators.
Running The Tests
Using pytest-bdd means that we can run the tests by running pytest as usual and our ‘BDD’ style tests should be run.