Introduction
Modern projects are increasingly placing high demands on automatic test coverage. Nowadays, writing tests is not just a sign of good tone, but one of the requirements for code. Increasingly, we hear such abbreviations as TDD (Test Driven Development) and BDD (Behavior Driven Development) and many strictly follow these approaches in development.
BDD is one of the varieties of TDD, and I would like to write about it in this article. More precisely, not about BDD itself, but about the frameworks that the industry provides for us today. And if to be completely accurate, then about three of them:
spock ,
easyb and
cucumber .
TDD and BDD
I will not refer here to articles and presentations of IT industry luminaries. I remember a phrase from Twitter about TDD which sat down in my mind, and which in my opinion clearly and briefly describes the TDD approach. Unfortunately, literally, I can’t give it, but the point is: “if you follow TDD, you can be 100% sure that each line of code was written due to the fallen test (s)”. I have seen and heard a lot of debates about the advantages and disadvantages of TDD and BDD, but a) tests should be written b) if the code was written due to a fallen test, then this code can be trusted and easily changed (refactored) without damaging the system .
Now, about BDD. This phenomenon appeared later and as Fowler argues in the article
“Mocks Aren't Stubs” due to the so-called Mokists. On the other hand, this approach is actively promoted by the guys from Agaile parties, minimizing the distance between developers, users and system analysts. This is achieved by obtaining Executable Scenarios, in other words, the scripts that describe the users are translated into an executable test. The BDD frameworks do this well.
We now turn to the comparison.
All examples describe the same scenario. I will omit the problem description with a solution that needs to be covered with tests, because the scripts themselves should clearly describe it.
The author of the article lists the implementation of BDD in order of increasing sympathy for them.
Easyb
This framework is written in
Groovy . Like all BDD implementations, it supports the Given-When-Then notation. Easily integrates into Continuous Integration (CI).
Here is an example script:
description "This story is about sqrt optimisation algorithm"
narrative "this shows sqrt optimisation", {
as a "java developer"
i want "to know how sqrt optimisation works"
so that "that I can pass google interview"
}
before "init input and expected result",{
}
where "complete scenarios data",{
input = [[5, 10, -3, 17, 12, 1, -2, 13, -12], [5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12]]
leftIndex = [2,3]
rightIndex = [5,10]
expectedSumm = [27,51]
}
scenario "find summ within two indexes #leftIndex and #rightIndex of the array #input",{
given "An Sqrt algorithm implementation",{
alg = new SqrtDecompositionSum(input.toArray(new int[0]))
}
when "calc sum between two indexes", {
actualSum = alg.calcSummBetween(leftIndex, rightIndex)
}
then "summ should be equal expected #expectedSumm", {
actualSum.shouldBe expectedSumm
}
}
Here is the result of the test:

It “climbs” the first drawback of easyb. The fact is that it is not clear where the two scenarios came from, while the described one is 1. If you look at the where section of the script, you can see that 2 sets of input and expected values ​​are being prepared. Unfortunately, the where construct is not documented even on
the project
site , at least I did not find it there.
Below is an example of a fallen test script.

')
As you can see the result is quite readable. Notice the line
actualSum.shouldBe expectedSumm
. This is a sugar that provides easyb to check the expected with the actual result.
In order to run the script from the IDE, you need to install the easyb plugin.
The second drawback I can note is that the last time the easyb update was in 2010, which in my opinion is quite a long time ago.
For details, refer to
the project
website .
Spock
Spock , like EasyB comes from groovy. Groovy / Grails developers love using it. Our script will look like this:
class SqrtSumAlgSpecTest extends Specification {
Algorithm alg
def "Sqrt sums scenarios"(){
when:
alg = new SqrtDecompositionSum(input.toArray(new int[0]))
then:
outputSumm == alg.calcSummBetween(leftIndex, rightIndex)
where:
input | leftIndex | rightIndex | outputSumm
[5, 10, -3, 17, 12, 1, -2, 13, -12] |2 |5 |27
[5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12] |3 |10 |52
}
}
Spock I like the where construct more. In order to create a spock specification, you need to create a groovy class inherited from
spock.lang.Specification
.
Below is an example of a fallen test script:

Spock, in my opinion, is closer to the developer than to the analyst or QA engineer, but still easy to read.
Cucumber
I got acquainted with
Cucumber quite recently, and the more I experimented with it, the more I liked it. Unlike the first two, Cucumber comes from Ruby. There is its implementation for Java and C #.
Cucumber scripts consist of two files: the actual script, and its implementation in Java, C #, Ruby. This allows you to separate the script from the implementation, which makes scripts absolutely ordinary narration in English, we give an example
Feature: Sqrt Sums Algorithm Feature
In order to ensure that my algorithm works
As a Developer
I want to run a quick Cuke4Duke test
Scenario Outline: Sqrt Sums Alg Scenario
Given The input array <input array>
When The calc sum between <Left index>, <Right index>
Then The summ is <output summ>.
Examples:
|input array |Left index |Right index|output summ|
|5, 10, -3, 17, 12, 1, -2, 13, -12 |2 |5 |27 |
|5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12 |3 |10 |52
By the way, scripts in cucumber are called features.
But the implementation
public class SqrtsumsalgFeature {
private Algorithm alg;
private int result;
@Given ("^The input array ([\\d\\s\\-\\,]*)$")
public void theInputArray(String input) {
String[] split = input.split(",");
int[] arrayInput = new int[split.length];
for (int i = 0; i < arrayInput.length; i++) {
arrayInput[i] = Integer.valueOf(split[i].trim());
}
alg = new SqrtDecompositionSum(arrayInput);
}
@When ("^The calc sum between ([\\d]*), ([\\d]*)$")
public void theCalcSumBetween(int L, int R) {
result = alg.calcSummBetween(L, R);
}
@Then ("^The summ is ([\\d]*).$")
public void theSummIs(int expectedResult) {
Assert.assertThat(result, is(expectedResult));
}
}
Here it is necessary to comply with Naming Conventions in the file names of the script and implementation, and in the names of the implementation methods and steps of the script. In other words, they must comply. Matching is achieved by using the
Given , @When,
Then , annotations and regular expression strings as arguments to the annotations.
Using groups of regular expressions, you can select the arguments of the methods of implementation.
Below is an example of a past cucumber test.

Here is an example of a fallen feature.

I like the separation of the script from its implementation. Someone may be confused by the use of regular expressions to “tie in” the implementation to the script, however, they are hidden from the script writer, and most developers are familiar with them, so I would not attribute this fact to shortcomings. For information about cuke4duke - implementations for Java, please go
here .
Total
The article was above average. I would also like to describe the integration with maven and Continuous Integration. I think that this will be the topic of the future post.
Write executable scripts, it is not only useful, but also enjoyable.