Cucumber is a popular open-source tool that supports Behavior-Driven Development (BDD) for testing software applications in Java. BDD emphasizes collaboration between developers, testers, and stakeholders by writing test scenarios in a readable, plain English language called Gherkin. This tutorial will guide you through the basics of setting up and writing your first Cucumber test in Java.
Building Blocks of Cucumber
Before diving into an actual example, let’s define which are the building blocks of Cucumber, which are features and scenarios.
- Features:
- A feature is a high-level description of a piece of functionality from the end-user’s perspective. It represents a set of related scenarios.
- Features are written in Gherkin, a plain text language with a specific syntax for defining features and scenarios.
- Features typically start with the
Feature:
keyword followed by a title and an optional description.
- Scenarios:
- A scenario is a specific example of how a feature should behave.
- A scenario is composed of a series of steps, which are written using Given, When, Then, And, and But keywords.
- Scenarios can have different outcomes (e.g., success, failure) depending on the steps and the behavior of the system.
Example:
In summary, features and scenarios are the building blocks of Cucumber. Together, they allow you to write executable specifications in plain text that can be used to drive development and testing.
Writing your first Cucumber Test
We will show here how to write a sample Cucumber test which integrates with other Testing Frameworks such as JUnit and RestAssured
Firstly, let’s define the Endpoint that we will be test:
@Path("/triangle") public class TriangleController { @GET @Path("area") public Response calculateArea(@QueryParam("base") double base, @QueryParam("height") double height) { double area = 0.5 * base * height; return Response.ok(area).build(); } }
Our Endpoint defines a single GET Endpoint to return the area of a Triangle. You can find the link to the full source code at the end of this article.
Next, let’s define our Feature and Scenario of our Cucumber Test:
Feature: Calculate Triangle Area Scenario: Calculate area of a triangle Given the base is 10.0 and the height is 5.0 When I call the area endpoint Then the response status code should be 200 And the response body should be 25.0
As you can see, the Cucumber Test defines the test scenario from the perspective of how the user interacts with the system, focusing on the expected behavior rather than low-level implementation details. This facilitates clearer test cases and promotes better overall system understanding.
Writing the Actual Cucumber Test Class
Then, here is the actual Test implementation which uses RestAssured to verify the assertions of the Cucumber Test:
public class TriangleSteps { private double base; private double height; private Response response; @Given("the base is {double} and the height is {double}") public void setTriangleProperties(double base, double height) { this.base = base; this.height = height; } @When("I call the area endpoint") public void callAreaEndpoint() { RestAssured.baseURI = "http://localhost:8080/democucumber/rest/"; response = RestAssured.given() .get("/triangle/area?base=" + base + "&height=" + height); } @Then("the response status code should be {int}") public void verifyStatusCode(int expectedStatusCode) { response.then().assertThat().statusCode(equalTo(expectedStatusCode)); } @Then("the response body should be {double}") public void verifyResponseBody(double expectedArea) { Double actualArea = Double.parseDouble(response.getBody().asString()); assertEquals(expectedArea, actualArea); } }
Here’s at high level what happens when you launch this Cucumber Test:
Parsing the Feature File:
- Cucumber starts by reading the feature file containing your scenarios written in Gherkin syntax.
- It identifies the scenario you want to test and extracts the steps defined with keywords like “Given”, “When”, “Then”, and “And”.
Executing “Given” Steps:
- Cucumber focuses on the first step, typically starting with “Given”.
- It searches for a matching step definition method in your code with the same signature (e.g.,
@Given("the base is {double} and the height is {double}")
). - Once found, it executes that method, which likely sets up the initial conditions for your test (e.g., storing base and height values).
Executing “When” Step:
- After the “Given” steps are complete, Cucumber moves on to the “When” step.
- It follows the same process as before, finding the corresponding step definition method and executing it.
- The “When” step typically triggers an action, like making an API request in your example.
Executing “Then” Steps:
- Finally, Cucumber executes the “Then” steps one by one.
- Each “Then” step definition verifies the outcome of the action triggered in the “When” step.
- This might involve assertions on response codes, data values, or other verification logic.
Activating the Cucumber Engine
Finally, to Bootstrap Cucumber Engine, include the following Class along with your tests:
import org.junit.platform.suite.api.ConfigurationParameter; import org.junit.platform.suite.api.IncludeEngines; import org.junit.platform.suite.api.SelectClasspathResource; import org.junit.platform.suite.api.Suite; import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME; @Suite @IncludeEngines("cucumber") @SelectClasspathResource("democucumber") @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty") public class RunCucumberTest { }
In simple terms:
- This class acts as a configuration file for your Cucumber tests.
- It specifies that you want to run them as a JUnit test suite, using the Cucumber engine, and tells it where to find the test scenarios (feature files) and how to format the test output.
Running the Cucumber Test
Firstly, we need to deploy the REST Resource. Since both the REST Endpoint and the Cucumber Test are in the same deployment, deploy first the application disabling the Tests:
mvn install wildfly:deploy -DskipTests=true
Then, you can execute your Cucumber Test suite:
mvn test
And here’s the result of your first Cucumber Test:
Conclusion
In this tutorial, we covered the basics of setting up Cucumber in a Java project and writing tests for a JAX-RS application. This is just a starting point, and you can expand upon it by writing more feature files and step definitions to cover different scenarios in your application.
Soruce code: https://github.com/fmarchioni/mastertheboss/tree/master/test/democucumber