An Introduction to Behavior-Driven Development

Origins of Behavior-Driven Development

  Is there a best way to develop software? Probably not. What we know is that there are several practices that try to ease our life when it comes to software development process. Every practice has its pros and cons. Different practices are suitable for different projects. Nevertheless, there is one practice that made an attempt to encompass the best agile techniques and make them more effective. This practice is called Behavior-Driven Development (BDD). The purpose of this paper is to introduce BDD and explain what does it have that other practices don’t.

  Behavior-Driven Development began its journey as an attempt to better understand and explain the process of Test-Driven Development (TDD). BDD is a refinement of practices stemming from TDD and Acceptance Test Driven Development (ATDD). [1] Therefore, in order to better understand BDD we should first take a look at where it all started, Test-Driven Development.

Test-Driven Development

  TDD is a software development practice that involves writing tests before writing the code being tested. The first step would be to write a small test, run it and observe its failure. Then the development team would start to write just enough code (no more!) to make that test pass. After the code is written and the test is passed, the design is analyzed and refactored if needed (e.g. remove duplications). In most testing systems a failed test is marked with a red color and the passed test is marked with a green one. As a result this TDD cycle is often called “red-green-refactor” (see the illustration below).


  As the red-green-refactor cycle repeats over and over again, the code base increases in size, more effort is focused onto the refactoring part. The design of the product is also in a developing phase, however it is not predetermined. That is what we call emergent design. Emergent design is one of the strongest aspect of TDD. In such software products, the design is driven by the technical requirements rather than planning the design ahead that might change (and probably will). [1]

  TDD should be seen as a technique of delivering high-quality code. It works great with Unit Tests. Therefore it is more of a developer oriented practice rather than a tester oriented one. Usually the developer writes the unit test and then starts to implement the solution so the test would pass.

Behavior-Driven Development

  As we already got some insights about TDD we can now take a look at what BDD actually is. BDD is about implementing an application by describing its behavior from the perspective of its stakeholders. What does that mean? It means that we need to understand the world from the point of view of our stakeholders. We should speak their language. Moreover, BDD is focused on the behavior of the product, not on its structure. We think in terms of interactions between people and systems or objects rather than we do about the structure of the system. [2]

  The BDD cycle is very similar to the TDD one. We start by creating an acceptance test (executable specification that describes behavior), then we write code that would make the test to pass. We repeat this cycle until the product is done.

TDD vs BDD

  Let’s analyse how BDD differ from TDD. TDD focuses more on the internal structure of the product, BDD on the other hand, is concerned about the behavior of the product, we don’t care how it was implemented, we focus only on the result. [5] Therefore, focusing on the internal structure is one of the greatest drawbacks of the TDD that BDD successfully removes. What an object does is significantly more important than what an object is. Moreover the stakeholder is not interested into the internal structure of the product. Take a look at the example below of a TDD test. [6]


  We test that after the tick() function is called the value of the counter should be 1. There is a problem here. The test is depended on the fact that the counter starts at 0. This fact represents an implementation detail and it is not relevant to the behavior of the tick() function. In other words we are interested only in the behavior of tick(), we shouldn’t care about the value of the counter.

  However, if the implementation of the counter is changed (e.g. the default value of the counter is set to 2), now after calling the tick() function we would get a result of 3 instead of the expected 1. Therefore we should modify the test itself even if the behavior of the tick() did not change. We end up having a dependency to the internal structure of the object being tested which is not good. Developing tests in such a manner might make the test suites expensive to maintain, every change in the internal structure (implementation) would mean refactoring several tests which rely on this structure. [4]

  Below is an example of the same test but adjusted according to BDD standards.


  In this BDD test we don’t care about the initial value of the counter. We are interested only in the behavior of the tick() method. We check that after the tick() was called the value of the counter has increased by one. This way we remove any unneeded dependency on the internal structure.

  TDD tests the internal structure (implementation) of the product while BDD tests its behavior. The latter is more important.

BDD Concepts

BDD Core Principles

  There are 3 core principles that BDD is based on:

  • Enough is enough – We should put just enough effort for the project to start. Anything more would be considered a waste. This also applies to automation. It is ok to have an automated build and deployment but we need to avoid automating everything.
  • Deliver stakeholder value – If what we do does not deliver value to our stakeholders then we should stop doing this and do something else instead.
  • It’s all behavior – We can describe the behavior of the product at any level of granularity.
Ubiquitous Language

  Ubiquitous language is one of the central techniques used in BDD.

  Many software projects suffer from communication issues that occur between the domain experts and the developers of the team. The domain experts and the developers often use different languages (jargon). Therefore a mental translation should be done from business to technical language and vice-versa. As a result the stakeholders vaguely describe what has to be implemented and the developers vaguely understand.

  To overcome this problem an ubiquitous language can emerge. Ubiquitous Language is a language structured around the domain model and used by all team members to connect all the activities of the team with the software. It was first introduced in Eric Evan’s “Domain-Driven Design” book. In other words, developers should speak the language of domain experts (stakeholders) to avoid miscommunication, delays and errors. [3]

  This common vocabulary should be used at all levels of software development life-cycle. The software should be designed to use the language of the domain. Moreover ubiquitous language should be used across the team on a daily basis in any meetings, email messages or chats. The goal is that everybody speaks the same language.

  By using an ubiquitous language we ensure that the friction of translating between everyone’s different terminologies is gone. Therefore the changes of misunderstanding are greatly reduced.

BDD Delivery Cycle

  The BDD delivery cycle starts with a stakeholder (usually product owner) discussing a requirement with the business analyst. The business analyst helps the stakeholder to split the requirement into features and maybe into smaller parts called stories.

  Next, both the business analyst and the stakeholder discuss with a tester to determine what does “definition of done” mean for each story. Then the testers design scenarios (future acceptance tests) that would describe the expected behavior of the product.

  Once the scenarios (specifications) are defined, for each story we automate these scenarios into “Acceptance Tests” and start implementing the code that would make these tests to pass. We repeat the process until all features/stories are done. [1]

Automated Acceptance Tests

  Acceptance tests specify what the software should perform in order for the business stakeholder to find it acceptable. Automated Acceptance Tests is the key technique that BDD provides. These tests represent real world examples. They are written as functional specifications, they show behavior. The tests are usually written in Gherkin or other Domain Specific Language (DSL). [2] They should be understandable to developers, testers and stakeholders. Recall ubiquitous language, when it comes to writing acceptance tests we should use ubiquitous language (use the vocabulary understood across all teams) as much as possible.

  Below is an illustrated example of some automated acceptance tests.


  As you can see, these tests represent real-world examples which are written as specifications (gives us information on how the system should work) and show behavior.

Acceptance Tests as Living Documentation

  Properly designed Acceptance Tests become more than just tests, they are executable specifications. They share the benefit of traditional specification documents, but they also can be executed by an automation test framework to show how accurate they are. Comparing it with the traditional documentation that usually is written once and then might go out of date, the automated acceptance tests become living specifications that reflect the real status of the project. Moreover having a single place to keep these tests that also represent documentation saves time and doesn’t add maintenance related issues. Gradually, acceptance tests become the definitive source of truth as to what the system does. [2]

References

  • 1. Chelimsky, D., Astels, D., Dennis, Z., Hellesoy, A., Helmkamp, B. and North, D. (2010). The RSpec Book
  • 2. Rose, S., Wynne, M. and Hellesoy, A. (2015). The Cucumber For Java Book
  • 3. Evans, E. (2003). Domain-driven design
  • 4. Your Boss Won’t Appreciate TDD: Try This Behavior-Driven Development Example, Available at: https://www.toptal.com/freelance/your-boss-won-t-appreciate-tdd-try-bdd
  • 5. What’s the difference between Unit Testing, TDD and BDD, Available at: https://codeutopia.net/blog/2015/03/01/unit-testing-tdd-and-bdd/
  • 6. The Difference Between TDD and BDD, Available at: http://joshldavis.com/2013/05/27/difference-between-tdd-and-bdd/
Share this article:

Ion Griu
QA Engineer