BDD Fundamentals

Introduction

Behavior Driven Development (BDD) provides techniques that can help you manage software development uncertainty and risk. BDD is about building the right software.

BDD was originally defined by Dan North in 2009 in London as an extension of TDD (Test Driven Development) that describes a cycle of interactions with particular outputs.

TDD is a technique used to make sure the code you write does what you expect. It consist of writing a failing test first and implementing the minimal amount of code that makes the test pass afterward. Then you will refactor the code to make it clean and apply design patterns. You will have to repeat the process for other scenarios or edge cases.

BDD techniques consist in identifying business goals and looking for features that will help deliver these goals, so that you should prioritize those features that will deliver the most value.

Behavior Driver Development can be applied to the UI layer and non-UI layers. When BDD is applied to the non-UI in a MVC application, you can easily apply these techniques to the controller layer.

BDD advantages:

BDD disadvantages:

Gherkin Syntax

Many BDD frameworks use a syntax known as Gherkin. This syntax is used to describe the requirements and expectations of a particular feature. Gherkin syntax usually follows the order of Given… When.. Then…:

Additionally, you can use And or But when multiple conditions or expectations are needed. e.g.

Given a transaction that is stored in our system with date before today
When I check the status from ATM channel
Then the system returns the status SETTLED
And the amount substracting the fee

BDD Steps

  1. Define business goal
  2. Find out what features are required to achieve the business goal
  3. Describe examples that will help understand how the features will work
  4. Write executable specifications to organize development and testing
  5. Write business logic

Business Goal

A Business goal is about delivering value. They should be translated into increasing revenues, decreasing costs, saving time… It’s important to have a fully understanding of the business context so you can react quickly if the requirements change. You can write business goals following any of these two templates:

In order to … As a … I want to …

In order to see the transaction status, amount and fee
As a user
I want to be able to retrieve a transaction.

As a … I want … so that …

As an user
I want to be able to retrieve a transaction
So that I can see the transaction status, amount and fee

These templates are commonly use in story cards.


Goals should be SMART:


Most of the time when you start a project you don’t really know what value you are supposed to deliver, that’s why it’s important to start conversations with product owners or stakeholders and ask the following questions:

Features

A feature is what we deliver to provide functionalities. A feature can be something like “get transaction status for a particular transaction”.

Developers and product owners should determine what features are needed to achieve a goal. When the features are discussed you need to describe them in more detail and prioritize those ones that will deliver the most value.

In an Agile project features are usually broke down into user stories. User stories will help us plan how we can deliver a feature and usually contain a short description of something small enough to deliver in a small iteration. Therefore, you might need several user stories to build an entire feature. We can also use an epic to group a set of stories that have something in common.

An epic describes a more general task and is usually implemented during a few Scrum sprints.

TP-101
Providing Transaction Status When Sending Transaction ID

As an user
I want to be able to retrieve a transaction
So that I can see the transaction status, amount and fee

When you implement a story you should get together with product owners, developers and testers to describe what the feature should do (Three Amigos, see below).

Three Amigos: Is a session in which three team members, a developer, a tester and a product owner, get together to discuss and write up an initial draft of the scenarios of a feature. They will define examples, use cases, point out technical considerations…

As we’ve seen, user stories are used as a tool to organize how we are going to deliver a feature, and you should only create stories when you are ready to start implementing the feature.

Examples and Executable Specification

Examples can be defined as the different scenarios for a particular features. Examples consist of a title that summarise what the example is trying to achieve; a description; a scenario title; a scenario body which contains a Gherkin structure given…when…then.

Feature: Return transaction status # feature title
  # description
  As an user
  I want to be able to retrieve the status of a transaction
  So that I can see the transaction status, amount and fee
  Scenario: Get transaction stored in our system given a channel # scenario title
    # scenario body
    Given a transaction that is stored in our system with date today
    When I check the status from CLIENT channel
    Then the system returns the status PENDING
    And the amount substracting the fee

It’s recommended to keep your scenarios simple by describing the behaviors with tables.

Executable specification acts as acceptance criteria and guideline for developers, so they are an excellent tool keep track of the progress of a feature.

You can use tools like Cucumber to write the executable specification.

@Given("a transaction that is stored in our system")
public void a_transaction_that_is_stored_in_our_system() {
  	Transaction transactionAfterToday = createTransaction(DATE_AFTER_NOW);
  	transactionService.save(transactionAfterToday);
}

As part of the executable specification we should include the living documentation. The living documentation is the reference or source of truth of how a feature works. This documentation is usually generated as a report by tools like Serenity BDD (previously called Thucydides).

Tips When Writing Executable Specification

Scenario: Get transaction stored in our system given a channel
  Given a transaction that is stored in our system with date before today
  When John Smith checks the status from CLIENT channel
  Then the system returns the status SETTLED
  And John Smith should see the amount substracting the fee

Business Logic

The implementation details will contain low level specification that interact with the system and is tested with unit-testing tools like JUnit. BDD can be also applied to unit testing with tools like Spock.

Steps to Implement a Scenario

As we mentioned before Developers should follow an outside-in strategy. You should start from the acceptance criteria and build the implementation details of what is required to make the acceptance criteria pass. Steps (the following examples are using Cucumber):

Scenario: Get transaction stored in our system given a channel
  Given a transaction that is stored in our system with date before today
  When I check the status from CLIENT channel
  Then the system returns the status SETTLED
  And the amount substracting the fee
@Given("a transaction that is stored in our system with date before today")
public void a_transaction_that_is_stored_in_our_system_with_date_before_today() {
    throw new PendingException();
}
@Test
void shouldSaveTransaction() {
    // WHEN
    transactionService.save(TRANSACTION);

    // THEN
    verify(transactionRepository).save(TRANSACTION);
}
public void save(Transaction transaction) {
    transactionRepository.save(transaction);
}