Organizations are increasingly taking steps to maximize the benefits of software testing. Many implement acceptance test scenarios while projects are still in development. This method is called Behavior Driven Development (BDD). BDD deploys test scripts written from both the developer's and the customer's perspectives using a collaboration process among developers, quality assurance testers, and customer representatives. There are different testing methodologies used in BDD. This post will discuss a popular mode called Cucumber.
Cucumber is a robust and reliable testing framework that adheres to behavior-driven development. Cucumber is a Ruby-based application that allows users to write acceptance use cases in plain text that non-technical business stakeholders can verify. Simple text can then be turned into executable tests written in the Gherkin programming language. Cucumber tests are essential because they can perform as an automation test script and a live document.
Feature files are the starting point with Cucumber tests. A feature file contains numerous scenarios that list them with multiple steps. Each step is executed one after another in Cucumber testing to mimic how the end-user interacts with the system. Sometimes one step state is required by another step in the scenario. Therefore, there must be a sharing of the state between the steps.
Sharing the state between the steps is challenging as the steps are in different step definition classes. If we have a single-step definition, we can share the state by creating Instance Variables, but as the scenario becomes more extensive, we need to develop separate step-definition classes based on functionality or domain. This is necessary because it is impossible to maintain a single-step definition class. This problem can be solved using the Static variable, but the state may be maintained between scenarios if we use the Static variable.
In this case, scenarios will be executed with unwanted static variables as they will not be cleared while running Java Virtual Machine (JVM). You have to reset the JVM to clear static variables, which can be a somewhat complex process. This is another instance where Cucumber comes to the rescue with its dependency on injection containers.
Cucumber offers various dependency injection containers for our use:
Below are three advantages dependency injection modules Cucumber offers:
Below is a framework diagram using Cucumber with the Spring Boot:
To understand how the state is shared between steps using Dependency Injection, create a feature file with one scenario and steps in different step-definition (PreferenceStepDefinition.java,FontStepDefinition.java,BorderStepDefinition.java,ResultStepDefinition.java) classes. Below is an example of a feature file and the Github source:
To use Dependency Injection, add Cucumber-Spring dependency on top of the Cucumber-Java and Cucumber-JUnit to develop cucumber tests using Java and Junit.
The CucumberIntegrationTest.class is the test entry point as shown in the Cucumber with Spring Boot framework diagram below.
Note that the @RunWith(Cucumber.class) annotation is used to instruct Junit to have Cucumber functionality.
The @CucumberOptions annotation enables the same options as in cucumber jvm command line, similar to using the following feature options: to specify feature path, glue option to specify step definition path, tags option for running specific tags, Plugin option for generating report specific format such as html, json etc.
The CucumberSpringConfiguration.class is the code that implements the dependency injection in Cucumber test cases.
The context configuration is accessed by the @CucumberContextConfiguration annotation. You do not need to change the configuration, nor to add extra beans because it is already configured by the CucumberSpringConfiguration class.
The configuration class can then be accessed by @SpringBootTest given we are using Spring.Boot.
Next, create the Pojo classes Border, Font with @Component annotation and use the Lombok annotations for getter and setter methods.
Then use @Scope(SCOPE_CUCUMBER_GLUE) to create the beans before the scenario’s execution.
@Scope(SCOPE_CUCUMBER_GLUE also removes the beans after the scenario’s execution to avoid sharing the state between scenarios.
2. The Step-definition for Font.class does the following:
3. The Step-definition Border.class does the following:
4. The Step-definition Result.class does the following:
After the scenario’s execution, the results below are displayed in the console.
Observing the results state, it has been shared between the multiple step-definitions without code instantiation.
We hope you now have gained a good sense of how to develop Cucumber with Spring Boot to help with your testing needs. You should also have a general understanding of how to:
Behavior Driven Development (BDD) methodology using Cucumber can be a great help to developers. It provides a chance for robust and reliable testing frameworks that can be easily deployed as we have shown in this article. Cucumber tests are truly effective and can be performed as automation test scripts with a live document. Nisum hopes that by using this method companies can improve their testing practices. If you want to check out the source code, you can clone it from GitHub.
Having the proper testing best practices can make or break a project or product. There are many products and services that promise to help you get past the testing hurdle but few have the knowledge and expertise that Nisum has in this field.
Let Nisum’s Testing and Automation Platform (TAP) Accelerator guide you to developing a best-in-class testing practice.
Nisum's Digital Services can assist your company with all aspects of your testing and digital transformation journeys. From DevOps to cloud development, to testing, Nisum is here to help guide you on your technology journey.