Benefits of Behaviour-Driven Development
1. Reduces rework caused by misunderstood or vague requirements
2. Reduces technical debt caused by reluctance to refactor code
3. Reduces slow feedback cycles caused by silos and hand-overs
4. Narrows the communication gaps between team members
5. Fosters better understanding of the customer
6. Promotes continuous communication with real world examples
Requirements
For the purpose of this tests I will use STS as workspace and very very important 1.5.12.RELEASE version of Spring. If you use the latest one you will be in trouble. And lastly, the latest version of the Cucumber plugin.
How to write simple test in plain English with Gherkin?
So, enough with the boring definitions. Let’s start with the work part.
The first thing you need to know about BDD with Cucumber is that you write your tests in plain English. The language itself is called Gherkin and resemble something like this:
Scenario: Hearing your snake you anticipate sound
Given I have hungry snake
When When I feed my snake
Then I receive snek snek
As you can see it is plain english. This way you are able to connect your business to your application. What is happening behind is that we are using annotations to mark our test code to the tests.
Dependencies required for this example
First create Spring starter project and change the version of Spring, because it will be set to the latests one.
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.12.RELEASE</version> <relativePath/>
Then add the dependencies needed for Cucumber and Junit
<dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-java</artifactId> <version>2.3.1</version> <scope>test</scope> </dependency> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-junit</artifactId> <version>2.3.1</version> <scope>test</scope> </dependency> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-spring</artifactId> <version>3.0.2</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency>
Simple functionality representing the test
Now for the purpose of the test we will have simple SnakeController which we will test.
@Controller public class SnakeController { private boolean fed; @Autowired public SnakeController() { super(); } public void feed() { fed = true; } public String poke() { if(this.fed == true) return "snek snek ^_^"; else return "hiss"; } }
File structure and good practices for storing your Gherkin tests. Writing your first test.
Until now – nothing new. Let’s continue to the tests. As I mentioned above all tests that are in the Gherkin language are simple files with .feature extension.You can create them everywhere in your project. It is a good practice to make folder in your src/test/resources and put them there.I prefer to add even a feature folder for personal preference. So you only need to create a file there with the feature extension and start writing tests. You have to end with something like this:
Then let’s add what we want to test in the feature file.
Feature: What does your snake say
I want to use this to check what snake says
Scenario: Hearing your snake you anticipate sound
Given I have hungry snake
When When I feed my snake
Then I receive snek snek
Creating runner responsible for the execution of your tests
We create a simple runner that will run our test code:
@RunWith(Cucumber.class) @CucumberOptions(plugin = { "pretty"}, features = { "src/test/resources/features" }) public class TestRunner { }
Make sure to notice that we are giving the destination of our feature file in the features argument.
The trick part.Creating @SpringBootTest glued to your Gherkin definitions.
Now it is becoming little tricky. We are going to run the tests with Spring so we need to make abstract class that will use the @SpringBootTest functionality and our Cucumber annotated tests are going to use it.
@RunWith(SpringRunner.class) @SpringBootTest public abstract class CucumberStepDefinitions { }
And at last we are gluing our step definitions from our feature file to our test code:
public class SnakeMeasureTest extends CucumberStepDefinitions { @Autowired SnakeController snake; @Given("^I have hungry snake") public void i_have_hungry_snake() { assertEquals("hiss", snake.poke()); } @When("^When I feed my snake$") public void when_i_feed_my_snake() { snake.feed(); } @Then("^I receive snek snek$") public void receive_snek_snek() { assertEquals("snek snek ^_^", snake.poke()); } }
Make sure to note that the Gherkin annotations from the feature file are above our test functions. In the end you have to run your test as simple Junit test and you should receive something like this in your console:
I hope you find the information useful. If you like what you have just read or have any questions, hit the comment button below.