Behavior-driven development using Python's 'behave' framework can help your team achieve better collaboration and test automation.

Get the newsletter

Have you heard about behavior-driven development (BDD) and wondered what all the buzz is about? Maybe you've caught team members talking in "gherkin" and felt left out of the conversation. Or perhaps you're a Pythonista looking for a better way to test your code. Whatever the circumstance, learning about BDD can help you and your team achieve better collaboration and test automation, and Python's behave framework is a great place to start.

What is BDD?

In software, a behavior is how a feature operates within a well-defined scenario of inputs, actions, and outcomes. Products can exhibit countless behaviors, such as:

Submitting forms on a website

Searching for desired results

Saving a document

Making REST API calls

Running command-line interface commands

Defining a product's features based on its behaviors makes it easier to describe them, develop them, and test them. This is the heart of BDD: making behaviors the focal point of software development. Behaviors are defined early in development using a specification by example language. One of the most common behavior spec languages is Gherkin, the Given-When-Then scenario format from the Cucumber project. Behavior specs are basically plain-language descriptions of how a behavior works, with a little bit of formal structure for consistency and focus. Test frameworks can easily automate these behavior specs by "gluing" step texts to code implementations.

Below is an example of a behavior spec written in Gherkin:

Scenario: Basic DuckDuckGo Search
Given the DuckDuckGo home page is displayed
When the user searches for "panda"
Then results are shown for "panda"

At a quick glance, the behavior is intuitive to understand. Except for a few keywords, the language is freeform. The scenario is concise yet meaningful. A real-world example illustrates the behavior. Steps declaratively indicate what should happen—without getting bogged down in the details of how.

The main benefits of BDD are good collaboration and automation. Everyone can contribute to behavior development, not just programmers. Expected behaviors are defined and understood from the beginning of the process. Tests can be automated together with the features they cover. Each test covers a singular, unique behavior in order to avoid duplication. And, finally, existing steps can be reused by new behavior specs, creating a snowball effect.

Python's behave framework

behave is one of the most popular BDD frameworks in Python. It is very similar to other Gherkin-based Cucumber frameworks despite not holding the official Cucumber designation. behave has two primary layers:

Behavior specs written in Gherkin .feature files

Step definitions and hooks written in Python modules that implement Gherkin steps

As shown in the example above, Gherkin scenarios use a three-part format:

Given some initial state

When an action is taken

Then verify the outcome

Each step is "glued" by decorator to a Python function when behave runs tests.

Installation

As a prerequisite, make sure you have Python and pip installed on your machine. I strongly recommend using Python 3. (I also recommend using pipenv, but the following example commands use the more basic pip.)

Gherkin features

The Gherkin syntax that behave uses is practically compliant with the official Cucumber Gherkin standard. A .feature file has Feature sections, which in turn have Scenario sections with Given-When-Then steps. Below is an example:

Feature: Cucumber Basket
As a gardener,
I want to carry many cucumbers in a basket,
So that I don’t drop them all.

@cucumber-basket
Scenario: Add and remove cucumbers
Given the basket is empty
When "4" cucumbers are added to the basket
And "6" more cucumbers are added to the basket
But "3" cucumbers are removed from the basket
Then the basket contains "7" cucumbers

Scenario Outlines always have an Examples table, in which the first row gives column titles and each subsequent row gives an input combo. The row values are substituted wherever a column title appears in a step surrounded by angle brackets. In the example above, the scenario will be run three times because there are three rows of input combos. Scenario Outlines are a great way to avoid duplicate scenarios.

Python mechanics

Every Gherkin step must be "glued" to a step definition, a Python function that provides the implementation. Each function has a step type decorator with the matching string. It also receives a shared context and any step parameters. Feature files must be placed in a directory named features/, while step definition modules must be placed in a directory named features/steps/. Any feature file can use step definitions from any module—they do not need to have the same names. Below is an example Python module with step definitions for the cucumber basket features.

Three step matchers are available: parse, cfparse, and re. The default and simplest marcher is parse, which is shown in the example above. Notice how parametrized values are parsed and passed into the functions as input arguments. A common best practice is to put double quotes around parameters in steps.

Each step definition function also receives a context variable that holds data specific to the current scenario being run, such as feature, scenario, and tags fields. Custom fields may be added, too, to share data between steps. Always use context to share data—never use global variables!

behave also supports hooks to handle automation concerns outside of Gherkin steps. A hook is a function that will be run before or after a step, scenario, feature, or whole test suite. Hooks are reminiscent of aspect-oriented programming. They should be placed in a special environment.py file under the features/ directory. Hook functions can check the current scenario's tags, as well, so logic can be selectively applied. The example below shows how to use hooks to set up and tear down a Selenium WebDriver instance for any scenario tagged as @web.

Other options

behave is not the only BDD test framework in Python. Other good frameworks include:

pytest-bdd, a plugin for pytest. Like behave, it uses Gherkin feature files and step definition modules, but it also leverages all the features and plugins of pytest. For example, it can run Gherkin scenarios in parallel using pytest-xdist. BDD and non-BDD tests can also be executed together with the same filters. pytest-bdd also offers a more flexible directory layout.

radish is a "Gherkin-plus" framework—it adds Scenario Loops and Preconditions to the standard Gherkin language, which makes it more friendly to programmers. It also offers rich command line options like behave.

lettuce is an older BDD framework very similar to behave, with minor differences in framework mechanics. However, GitHub shows little recent activity in the project (as of May 2018).

Any of these frameworks would be good choices.

Also, remember that Python test frameworks can be used for any black box testing, even for non-Python products! BDD frameworks are great for web and service testing because their tests are declarative, and Python is a great language for test automation.

Topics

About the author

Andrew Knight - I am a software engineer with expertise in development, testing, and automation. My specialty is building automated test frameworks. I write a software blog at AutomationPanda.com. My favorite language is Python, but I also enjoy using Java, C#, and JavaScript.

Footer

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat.

Opensource.com aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. Red Hat and the Shadowman logo are trademarks of Red Hat, Inc., registered in the United States and other countries.