An introduction to what is Behaviour Driven Development and how crucial it is in software development. In this blog post, I’ll be briefly comparing TDD to BDD, going through a few good practices in writing BDD scenarios and how we use BDD at DeltaX.
Behaviour Driven Development (BDD)
Behaviour-Driven Development (BDD) is a set of practices that aims in:
Reducing the rework caused by misunderstood or vague requirements
Helping a layman understand what the software does
Helping add new feature/module to a project by keeping the core behaviour of the software intact
Behavior-driven development is an extension of test-driven development; development that makes use of a simple, domain-specific scripting language. It is a closer relationship to acceptance criteria for a given function and the tests used to validate that functionality. Over the years, many people developed BDD frameworks, finally framing it as a communication and collaboration framework for developers, QA and non-technical or business participants in a software project.
BDD implementation overview
Usually, BDD for a software revolves around a feature file written in Gherkin syntax. Each feature file consists of the core features of the software. Each feature in this file consists of different scenarios , that are a way of explaining (in plain english) how a given feature should behave in different situations or with different input parameters. Do read more on how to write feature files here.
The scenarios are written in steps using the keywords
But in plain English. The implementation details of these steps are hidden in step definitions. A Step definition is usually a block of code written in any coding language that implements core logic of the step.
Simple BDD example
Suppose you are assigned to develop a software for an ATM machine that dispenses cash.
If you are following a BDD approach to software development, you should first write a feature file covering all the scenarios. Given that the account has a particular amount of balance, the debit card is valid and the machine contains enough money, there can be two significant scenarios when account holder tries to withdraw cash i.e he should be able to withdraw cash or not.
Feature: Account Holder withdraws cash Scenario: Account has suffecient funds Given the account balance is "100" rupees And the card is valid And the machine contains enough money When the Account Holder requests "20" rupees Then the ATM should dispense "20" rupees And the account balance should be "80" rupees And the ATM should alert the user with "Available balance is 80 rupees" And the card should be returned Scenario: Account has insufficient funds Given the account balance is "100" rupees And the card is valid And the machine contains enough money When the Account Holder requests "150" rupees Then the ATM should alert the user with "insufficient funds" message And the card should be returned
Once you get this feature file reviewed and approved by the project assignee or the person in charge that the acceptance criteria and feature requirements are met, you should start implementing the step-definitions for each step.
Before implementing the step-definitions, all the tests should be failing as you have not implemented them yet.
After implementing the step-definitions, all the tests should be passing. These step-definitions will have the code logic that perform a particular function.
A few good practices to be followed during BDD
Over the past few months, I have been working on a good number of DeltaX services, especially tracking services, be it writing a new service, adding a new feature to an existing service, modifying the architecture/functionality or simply just refactoring the code. In all these cases, it was BDD that ensured that the core functionality and behaviour of the service is intact. Here are some things that might help you next time you’re writing a new feature file or editing an existing one:
Try to cover all the scenarios that can occur for a feature. (Reduces the amount of hotfixes that might later be assigned to you :P)
Your tests must be idempotent, which means that the BDD tests must be passing whether you run it for any number of times.
Since most of our services deal with tons of shared data (i.e data from table A is used in multiple services), it is important that the data you test on should not be altered by other developer’s tests and similarly your tests should not alter existing data. To ensure this, ideally, you should be testing only on dummy data that you insert before the test and wipe off that dummy data once the testing is complete. Use BeforeScenario, AfterScenario, BeforeFeature and AfterFeature for this.
Try to have your scenarios written in plain simple english, and avoid any technical definitions. This will help new developers to understand your software easily.
Use tags in your scenarios to avoid code/text redundancy.
Test Driven Development (TDD)
Test-Driven Development (TDD) is a software development technique where automated tests are written before the code. Developers use those tests to drive the development. I won’t be going too deep into TDD, therefore the image below should be sufficient to have a basic understanding of TDD:
TDD vs BDD
Both approaches(BDD and TDD) start with writing a failing test and then picking it up from there.In BDD, a test is written that can satisfy both the developer and someone who is not into the technical aspects of the software, but in TDD you write a test that will only satisfy a developer and the code they write. BDD works over TDD. So you can never say that BDD and TDD are entirely two different things. Therefore, there is absolutely no harm in implementing both approaches: one to support the quality of the code the developer writes, and the other to support the behavior of the system defined by the product owner.
To sum up,
In TDD, I do not care much about the output. The only thing needed is to carry out the test in a particular way.
In BDD, I do not mind how you come up with the output, only that the output has to be correct under the GIVEN condition.