The examples in this article are created with:
The examples are available for download.
What is BDD and Cucumber?
Behaviour-Driven Development (BDD) is a collaborative approach to software development that bridges the communication gap between business and IT. BDD helps teams communicate requirements with more precision, discover defects early and produce software that remains maintainable over time.
It helps teams create business requirements that can be understood by the whole team. Specifying examples uncovers misunderstanding people might not even be aware of. Teams that practice BDD focus on preventing defects rather than finding them. This leads to less rework and quicker time to market.
The two main practices in the BDD approach are discovery workshops, which bridge the communication gap between business and IT, and executable specifications.
— Cucumber — BDD Tutorial
Cucumber is a tool that supports Behaviour-Driven Development(BDD).
Cucumber reads executable specifications written in plain text and validates that the software does what those specifications say. The specifications consists of multiple examples, or scenarios.
In order for Cucumber to understand the scenarios, they must follow some basic syntax rules, called Gherkin.
— Cucumber — Introduction
My first reaction when reading about BDD was, “It sounds like yet another business consulting word-soup.”
Also, I felt that BDD was redundant as I already have embraced integration testing, i.e., testing features, not modules. See Revisiting React Testing in 2019for more on that.
Enter Jest Cucumber
Just about when I was about to give up on BDD and Cucumber, I stumbled upon Jest Cucumber.
jest-cucumber is an alternative to Cucumber.js that runs on top on Jest. Instead of using describe and it blocks, you instead write a Jest test for each scenario, and then define Given, When, and Then step definitions inside of your Jest tests. jest-cucumber then allows you to link these Jest tests to your feature files and ensure that they always stay in sync.
— Jest Cucumber — Jest Cucumber
While this looked promising, their example was overly abstract:
Feature: Rocket Launching
Scenario: Launching a SpaceX rocket
Given I am Elon Musk attempting to launch a rocket into space
When I launch the rocket
Then the rocket should end up in space
And the booster(s) should land back on the launch pad
And nobody should doubt me ever again
The Missing Basic Example
While there are better examples for the more complicated Jest Cucumberfeatures, let us create a basic example.
Let us say we have a module that sums two numbers, src/utils/sum.ts:
and we have an integration (actually unit in this case) test:
Let us approach this feature using a BDD approach using Jest Cucumber. First, we write the specifications in Gherkin syntax, src/features/sum_a_pair.feature:
note: After learning a bit more about the theory of BDD, I have come to realize this example is not the best as it really does not have an initial (Given) state; suppling the two numbers should happen in the When clause.
We then implement the test steps, src/features/step_definitions/sum_a_pair.steps.test.ts:
- My initial reaction is that this looks like a lot of boilerplate for little benefit
An More Interesting Basic Example
The basic example only included a single scenario, adding 1 and 2. We might want to test some other example pairs. This is easy to specify using Gherkinsyntax, src/features/sum_pairs.feature:
We then implement the test steps, src/features/step_definitions/sum_pairs.steps.test.ts:
- The specification is starting to look more useful
- With not much more code than our last example, we can handle the additional scenarios
The Missing React Example
Now let us look at a React example; say we have a feature that displays a counter value (starting at 0) and pressing the minus button decrements the value and plus button increments it.
A simple implementation would be:
The integration test, src/components/Counter/Counter.test.tsx:
Let us approach this feature using a BDD approach; creating a Gherkinspecification for this feature, src/features/counter.feature:
We then implement the test steps, src/features/step_definitions/counter.steps.test.ts:
- Even with this most simple of examples, we can start to see the value of this more declarative approach; at a glance it is more clear what the tests do
- It is also intriguing that we can share the Gherkin specification with non-developers, e.g., the business analysts
In the end, I have come to begin to value the approach that BDD (with Gherkin syntax) has on the complete development cycle; from feature generation, to development, testing, and acceptance.
Also, with Jest Cucumber, the transition from more traditional Jest testing was seamless.