Practicing behaviour driven development

 

Gherkin – Cucumber – Test – Code

One of the prominent challenges in establishing software development lifecycle is the traceability. The ability to trace a need to something functioning inside the computer as software is a monumental problem. Glittering jargons, frameworks and new technology push their claim to solve many modern-day problems. Here is this problem from the initial days that hardly gets the attention it requires. Looking at the attention given to this problem, one will agree there is far and few solution candidates. This is partly because of the nature of the problem and the willingness of developers, and sponsors to recognize this as a problem in the first place let alone recognising it as a big problem.

By nature, this problem is something that cannot be solved alone by a framework, library or system. Ideal solution will to this problem will always be part software and part human process. Needless to point out human involved in the process are both developers and stakeholders. No matter how much fancier and shinier the software gets it cannot solve this problem until the team involved in building the software gets the human process correct as well.

Cucumber is one such far and few solutions option available in the industry to address this problem. It is only a candidate that aims to solve the software component. But has good interfaces to the human process. Let us first elaborate on what we mean by human process. Cucumber requires that the need i.e., requirement for the software be written in Gherkin format which looks like this –

Feature: Show popular posts only from selected subreddits

 Currently reddit lists popular posts from all over the subreddits. In this feature we extend that behaviour and allow the user to filter certain subreddits and in the popular posts.

 Scenario: When I do not select any subreddit

   Given No subreddit is selected

   When I go to popular posts

   Then I should see all popular posts across all subreddits

 

This is a nifty way of expressing what is required which has some structure as well for it i.e., Feature-Scenario-Given-When-Then. This proto-structure if we could call that is the interface to the human process. Process defines who writes the above statements and how it flows through the lifecycle. Thus, this proto-structure must be used to define the need and used throughout the lifecycle.

Challenge #1 Who and when feature file is defined

The most practical way is to not treat this as complicated stuff that must be done by developers to technical business analysts. That proto-structure must be developed as part of requirements discovery by the business analyst. Right along with stakeholders who define the need. Overtime that proto-structure stored in a feature file must flow through the lifecycle process. If one misses to write this file along the discovery sessions, trust us it will never get done or will be done with half intent and become the burden which every team member wants to unload and move faster.

Challenge #2 How is the test code written

Next that is forte and core strength to cucumber is the software component of it. This feature file will be converted to tests that act as assurance to software developers that their code fulfils the need. Notice the loose usage of the word test. It is intentional to skip the nature of test. Thus, developer has the complete freedom to mix both unit and integrated tests together to accomplish the goal – Functional and working software.

That creeps in another challenge – How do you define and maintain both unit and infrastructural tests in the same place. Additionally, that gives jitters is what will happen to the state of the system after these tests are run? How does integrated tests ensure state of the system is reset after every run?

Let us take one step at a time. Let us first define how both unit and integrated tests run in the same place. We assume you use Java language for the Cucumber’s library. With that assumption your feature test will look like this –

package reddit.custom.extension;

import io.cucumber.java.en.Given;

import io.cucumber.java.en.When;

import io.cucumbr.java.en.Then;

import static org.junit.jupiter.api.Assertions.*;

public class FeatureStepDefinitions {

 private String specifiedSubReddits;

 private Vector<String> listedPosts;

 @Given(“No subreddit is selected”)

 public void no_subreddit_is_selected() {

   // TODO: Write test code here.

 }

 @When(“I go to popular posts”)

 public void i_go_to_popular_posts() {

   // TODO: Write test code here.

 }

 @Then(“I should see all popular posts across all subreddits”)

 public void i_should_see_all_popular_posts_across_all_subreddits() {

   // TODO: Write test code here.

 }

}

 

The name of the methods by convention is the declarative part of the respective statements. However, one is free to change as far as the meaning is conveyed. The important part that gives the flexibility is the Cucumber framework only defines the semantic mapping to the Given, When, and Then by the use of attributes decoration. The test framework to be used is still defined by the developer. Notice the import statement for org.junit.jupiter.api.Assertions.*. You can very well use any other framework or for that reason make calls to your own API’s like in an integration testing. If you are diminished the purpose of the Cucumber framework to just the custom attributes/decoratorsthen focus once again in the same decorators. They have got these parameters. These parameters are the replica of statements in the feature file.

That is the mortar which binds the feature file to the test. There are two types of mappers used. One which is more developer oriented i.e., using regular expressions. That is the parameter to the decorator should be a regular expression that yields a specific match to the Given in the feature file. The another is a Cucumber expressions which is more friendly but has a micro-syntax to be remembered.

If you are still wrapping around the point – it can be anything; here is a example for the interesting method – i_go_to_popularposts

HttpClient client = HttpClient.newBuilder().build();

   HttpRequest request = HttpRequest.newBuilder()

           .uri(URI.create(“http://localhost:7790/reddit_popular”))

           .POST(BodyPublishers.ofString(…))

           .build();

   HttpResponse<?> response = client.send(request, BodyHandlers.discarding());

   System.out.println(response.statusCode());

 

Above code uses HTTP client to issue a request to controller will be built with parameters relating to the empty selection of subreddit (the three dots – it can be a json, string or some other datatype). This style resembles to the integration testing. Where as the following one liner resembles to the unit test style tests –

RedditExtension.NewPopular(…)

 

We hope this settles any doubt you might have on the nature of tests that could be written along with Cucumber framework. There are other challenges that are yet to be addressed but we will park that for a future dispatch.