Behavior-driven development (BDD) is a software development process that attempts to solve the problem of implementing poorly defined requirements. It seeks to leverage the domain expertise of business and QA professionals to ensure that developers build the correct software.
Let’s begin by describing the evolutionary process that has prompted many organizations to explore BDD.
At some point, your organization decided it needed to accelerate releases and get to the market faster. You transitioned to agile to achieve these goals. You may not be pure agile, but you’re scrumming, working in sprints, and releasing frequently.
Testing, however, often becomes a bottleneck during the transition to agile as QA struggles to keep pace with development. In response, you probably integrated testing into your pipeline to alleviate the verification and validation blockers that threatened to wipe out the productivity gains you made by transitioning to agile.
At this point, you’re not only developing faster, but simultaneously ensuring software quality with continuous testing practices. But how do you know that you have built the right thing? Sure it works, but is it what customers want—or need?
If this process sounds familiar, then you are probably reading this article as part of a research project with the goal of implementing behavior-driven development (BDD). BDD is intended to ensure that the requirements guiding your development efforts are well-defined and implemented correctly.
BDD versus TDD
Many people view BDD as an evolution of the test-driven development (TDD) methodology. In TDD, developers write the test before writing the code. Developers, furthermore, should only write enough code to ensure that a test passes. The result is lean and mean code with a high level of coverage.
By itself, however, TDD does not necessarily translate to code that embodies well-defined requirements. It only ensures that the code is covered by tests. TDD is also tricky to implement because you can’t write an executable test until you have something to execute the test against.
Rather than focusing on the test, the focus in BDD is on defining the behavior you want to implement. Rather than writing code to pass the test, developers write code that implements the behavior. The difference is subtle but significant.
Behaviors are defined in human-readable form according to a specific format:
GIVEN x (precondition)
WHEN y (event)
THEN z (outcome or outcomes)
Behaviors can also include AND and BUT statements to define more complex initial contexts, events, and outcomes.
This format accomplishes a few things. First, it forces developers to think more about not only how the requirements should be implemented, but how to implement them in a way that’s testable. And because behaviors are relatively simple to define, it enables business analysts and other non-developer members of the organization to contribute their domain expertise to the project. Finally, the behavior format also enables you to specify each statement in a modular way so that a BDD tool, such as Cucumber, Specflow, or Behat, can perform additional operations to simplify test verification.
Behavior statements are commonly grouped into blocks that can be thought of as (test) scenarios. The “scenarios” are collected in a “feature file” that is mapped to a series of modular subtests. Testers assemble these subtests to validate the behavior of the application.
Everyone in the organization stands to benefit from the BDD model. As long as developers write the behaviors into the code, they don’t need to worry that they’re building the right thing. BDD practices also ensure that code is written with testability in mind. For testers, the complexity of test creation is greatly reduced. The ability to write scenarios in a human-readable format makes it easier to turn a requirement into a test. Project managers get to leverage the domain expertise of other people in the organization to contribute to the verification process, freeing up expensive developer resources to focus on building the right application.
The BDD workflow
There are essentially three parts to BDD:
- Define: A business analyst or other domain expert writes behaviors into a feature file and shares it with a team. The behaviors documented in the feature file are written as modular sentences.
- Create: Developers write code that implements the behaviors in the feature file, as well as “glue code,” which is code that maps behaviors to some kind of execution. For example, the following GIVEN behavior may map to glue code that calls an API to get a user ID:
GIVEN I am user 12212
AND using funds from account 13344
WHEN I create a new loan account
THEN A new loan account should exist
- Verify: Testers process the feature file against the glue code to verify that the application code matches the behaviors. This is usually done using a BDD tool. As a result, an executable form of the feature file is compiled and executed to validate the functionality.
BDD tools may have their own terminologies and syntax. Gherkin, for example, is a language for writing feature files associated with the Cucumber BDD tool. The behaviors in the feature file map to “step definitions” (or simply “step-defs”) programmed in the glue code. Step-defs are written in a programming language, such as Java or .NET. Cucumber, itself, is simply an engine that parses the behaviors in the feature file against the glue code and assembles tests in JUnit or some other framework, depending on which implementation of the tool you are running. As a result, testers are able to automatically generate tests based on requirements that encapsulate expected behaviors.
There are clear benefits associated with BDD, but implementation, especially at the enterprise level, is still fraught with challenges. BDD is about solving the problem of building the right functionality—not the usual problems of how to improve code quality or achieve greater velocity.
Challenges of implementation
In BDD, when writing step definitions, developers need to write code that defines what should happen when a test step that matches the definition is executed. Some test automation tools can reduce the technical barrier to implementing BDD by allowing non-developers to write step-defs using a simpler syntax than Java, .NET, or another programming language. The tool can then execute the step-defs as automated tests.
For example, a step definition may reference an individual test that makes a call to a REST API. A second step definition might reference another test that validates the response data from a different REST API. A third step definition might reference a test that executes a DB query and validates data in the result set.
Each automation tool provides a different mechanism for working with BDD tools, but the following steps describe the general process:
- Create a library of one or more tests that contain test steps and/or test scenarios to be referenced by the step definitions.
- Map behaviors in the feature file to the test steps.
- As the BDD scenario is executed, the test steps are copied from the workspace into a new test that defines the scenario.
- Once all the steps are assembled, the module will execute the scenario via the automation tool. The results will also be reported back to the BDD tool.
As a result, the test automation tool gives more control to the testers. Their confidence that they’ve completely covered the functionality under test is also reinforced. Leveraging a mature, feature-packed, end-to-end testing solution provides an easy entry into test automation, test maintenance, and a natural integration into existing CI/CD workflows. At a high level, it enables organizations to leverage less technical resources in the organization to implement BDD, freeing up development resources.