In TDD, the term “Acceptance Tests” is misleading. Acceptance tests actually represent the expected behavior of the system. In Agile practices, collaboration of the whole team and interactions with the customer and other stakeholders is emphasized. This has given rise to the necessity of usage of terms that are easily understood by everyone involved in the project.
TDD makes you think about the required Behavior and hence the term ‘Behavior’ is more useful than the term ‘Test’. BDD is Test Driven Development with a vocabulary that focuses on behavior and not tests.
In the words of Dan North, “I found the shift from thinking in tests to thinking in behavior so profound that I started to refer to TDD as BDD, or Behavior Driven Development.” TDD focuses on how something will work, BDD focuses on why we build it at all.
BDD answers the following questions often faced by the developers −
Question | Answer |
---|---|
Where to start? | outside-in |
What to test? | User Stories |
What not to test? | anything else |
These answers result in the story framework as follows −
Story Framework
As a [Role]
I want [Feature]
so that [Benefit]
This means, ‘When a Feature is executed, the resulting Benefit is to the Person playing the Role.’
BDD further answers the following questions −
Question | Answer |
---|---|
How much to test in one go? | very little-focused |
What to call their tests? | sentence template |
How to understand why a test fails | documentation |
These answers result in the Example framework as follows −
Example Framework
Given some initial context,
When an event occurs,
Then ensure some outcomes.
This means, ‘Starting with the initial context, when a particular event happens, we know what the outcomes should be.’
Thus, the example shows the expected behavior of the system. The examples are used to illustrate different scenarios of the system.
Let us consider the following illustration by Dan North about an ATM system.
As a customer,
I want to withdraw cash from an ATM,
so that I do not have to wait in line at the bank.
There are two possible scenarios for this story.
Scenario 1 − Account is in credit
Given the account is in credit
And the card is valid
And the dispenser contains cash
When the customer requests cash
Then ensure the account is debited
And ensure cash is dispensed
And ensure the card is returned
Scenario 2 − Account is overdrawn past the overdraft limit
Given the account is overdrawn
And the card is valid
When the customer requests cash
Then ensure a rejection message is displayed
And ensure cash is not dispensed
And ensure the card is returned
The event is same in both the scenarios, but the context is different. Hence, the outcomes are different.
The Development Cycle for BDD is an outside-in approach.
Step 1 − Write a high-level (outside) business value example (using Cucumber or RSpec/Capybara) that goes red. (RSpec produces a BDD framework in the Ruby language)
Step 2 − Write a lower-level (inside) RSpec example for the first step of implementation that goes red.
Step 3 − Implement the minimum code to pass that lower-level example, see it go green.
Step 4 − Write the next lower-level RSpec example pushing towards passing Step 1 that goes red.
Step 5 − Repeat steps Step 3 and Step 4 until the high-level example in Step 1 goes green.
Note − The following points should be kept in mind −
Red/green state is a permission status.
When your low-level tests are green, you have the permission to write new examples or refactor existing implementation. You must not, in the context of refactoring, add new functionality/flexibility.
When your low-level tests are red, you have permission to write or change implementation code only for making the existing tests go green. You must resist the urge to write the code to pass your next test, which does not exist, or implement features you may think are good (customer would not have asked).