Last Updated On
In this tutorial, we will implement a framework to test the APIs using Serenity BDD with Cucumber and Rest Assured.
Table of Contents
- What is Serenity BDD?
- What is Rest Assured?
- Prerequisite
- Dependency List
- Project Structure
- Implementation Steps
- Update Properties section in Maven pom.xml
- Add dependencies to POM.xml
- Update the Build Section of pom.xml
- Create a Feature file in src/test/resources
- Create the Step Definition class or Glue Code
- Create Serenity Test Runner
- Create serenity.properties file
- Serenity Tests Execution
- Verify the Serenity Reports
What is Serenity BDD?
Serenity BDD is an open-source library that aims to make the idea of living documentation a reality.
What is Rest Assured?
Rest Assured is one of the most powerful libraries for testing RESTful API using Java language. Rest-Assured is a Java-based library that is used to test RESTful Web Services. This library behaves like a headless Client to access REST web services. The Rest-Assured library also provides the ability to validate the HTTP Responses received from the server. For e.g. we can verify the Status code, Status message, Headers, and even the Body of the response. This makes Rest-Assured a very flexible library that can be used for testing. In this post, we will learn how to write high-quality, expressive REST API tests using Rest Assured and Serenity BDD.
Prerequisite
- Java 17 installed
- Maven installed
- Eclipse or IntelliJ installed
Dependency List:
- Java 17
- Maven – 3.9.5
- Serenity – 4.0.18
- Serenity Rest Assured – 4.0.18
- Serenity Cucumber – 4.0.18
- Rest Assured – 5.3.2
- JUnit – 4.13.2
- Maven Surefire Plugin – 3.2.1
- Maven Failsafe Plugin – 3.2.1
- Maven Compiler Plugin – 3.11.0
Project Structure

Implementation Steps
Step 1 – Update Properties section in Maven pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<serenity.version>4.0.18</serenity.version>
<serenity.cucumber.version>4.0.18</serenity.cucumber.version>
<rest.assured.version>5.3.2</rest.assured.version>
<junit.version>4.13.2</junit.version>
<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.2.1</maven.failsafe.plugin.version>
<tags></tags>
</properties>
Step 2 – Add dependencies to POM.xml
Add Serenity, Serenity Cucumber, Serenity Rest Assured, Rest Assured, and JUnit dependencies to POM.xml
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber</artifactId>
<version>${serenity.cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-rest-assured</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest.assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Step 3 – Update the Build Section of pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<parallel>methods</parallel>
<useUnlimitedThreads>true</useUnlimitedThreads>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>net.serenity-bdd.maven.plugins</groupId>
<artifactId>serenity-maven-plugin</artifactId>
<version>${serenity.version}</version>
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-single-page-report</artifactId>
<version>${serenity.version}</version>
</dependency>
</dependencies>
<configuration>
<tags>${tags}</tags>
<reports>single-page-html</reports>
</configuration>
<executions>
<execution>
<id>serenity-reports</id>
<phase>post-integration-test</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The complete pom.xml looks like as shown below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SerenityCucumberRestAssuredDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SerenityCucumberRestAssuredDemo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<serenity.version>4.0.18</serenity.version>
<serenity.cucumber.version>4.0.18</serenity.cucumber.version>
<rest.assured.version>5.3.2</rest.assured.version>
<junit.version>4.13.2</junit.version>
<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.2.1</maven.failsafe.plugin.version>
<tags></tags>
</properties>
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber</artifactId>
<version>${serenity.cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-rest-assured</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest.assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<parallel>methods</parallel>
<useUnlimitedThreads>true</useUnlimitedThreads>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>net.serenity-bdd.maven.plugins</groupId>
<artifactId>serenity-maven-plugin</artifactId>
<version>${serenity.version}</version>
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-single-page-report</artifactId>
<version>${serenity.version}</version>
</dependency>
</dependencies>
<configuration>
<tags>${tags}</tags>
<reports>single-page-html</reports>
</configuration>
<executions>
<execution>
<id>serenity-reports</id>
<phase>post-integration-test</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Step 4 – Create a Feature file in src/test/resources
Create a features folder within src/test/resources to create test scenarios in the Feature file. Test Scenarios are created in a Feature File which contains an overall description of a feature as well as a number of scenarios. Feature files can be placed in different locations, but you can reduce the amount of configuration you need to do with serenity if you put them in the src/test/resources/features directory. In this feature file, will send a request, and the response should be of status “200” and employee name of “Tiger Nixon”. The feature file looks something like this:
Feature: Employee Details
@GetEmployee
Scenario: Get the details of employee
Given I send a request to endpoint
Then the API should return status 200
And Response should contains employee name "Tiger Nixon"
Step 5 – Create the Step Definition class or Glue Code
To use Rest-assured, Serenity provides class SerenityRest
import net.serenitybdd.rest.SerenityRest;
It is a Java method with an expression that is used to link it to Gherkin steps. When Cucumber executes a Gherkin step, it will look for a matching step definition to execute. These use annotations like @given, @when, and @then to match lines in the scenario to java methods
package org.example.definitions;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import static org.hamcrest.Matchers.equalTo;
public class EmployeeDefinitions {
private static final String URL = "http://dummy.restapiexample.com/api/v1/employee/1";
public Response response;
@Given("I send a request to endpoint")
public void sendRequest() {
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json")
.when().get(URL);
}
@Then("the API should return status {int}")
public void verifyResponse(int status) {
SerenityRest.restAssuredThat(response -> response.statusCode(status));
}
@And("Response should contains employee name {string}")
public void verifyResponseContent(String expectedEmployeeName) {
SerenityRest.restAssuredThat(response -> response.body("data.employee_name", equalTo(expectedEmployeeName)));
}
}
Step 6 – Create Serenity Test Runner
Cucumber runs the feature files via JUnit and needs a dedicated Test Runner class to run the feature files. When you run the tests with serenity, you use the CucumberWithSerenity test runner. If the feature files are not in the same package as the test runner class, you also need to use the @CucumberOptions class to provide the root directory where the feature files can be found. It is the starting point for JUnit to start executing the tests. TestRunner class is created under src/test/java. The test runner to run all of the feature files looks like this:
import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(plugin = { "pretty" }, features = "src/test/resources/features/Employee.feature", glue = {
"org.example.definitions" })
public class SerenityAPITestRunner {
}
Step 7 – Create serenity.properties file
Serenity.properties file is created at the root level.
serenity.project.name = Rest API Testing using Serenity, Cucumber and JUnit4
Step 8 – Serenity Tests Execution
You can run the tests from SerenityAPITestRunner or from the command line by
mvn clean verify
Test Execution Page looks like this as shown below image

Step 9 – Verify the Serenity Reports
A number of reports are generated, but we are concerned about index.html and serenity-summary.html.
The report is well-formatted and contains consolidated results. Reporting is one of the major pillars of Serenity. Serenity Report not only reports on whether a test scenario passes or fails but documents what it did, in a step-by-step narrative format. The below pic illustrates the test results for our first acceptance criteria:
The test report generated by Serenity is placed under target/site/serenity/index.html.
Index.html
The first tab is called “Overall Test Results” and it provides information about test statistics. This Overall Test Result shows the Scenario Results (No Of Test Cases Pass, No Of Test Cases Failed, No of Test Cases Pending, No Of Test Cases Ignored, No Of Test Cases Skipped).


In the below pic, the report shows the test scenario steps status and time taken for each step to execute.

With the use of the REST Query button, it’s possible to display query details. Visible details:
Path, Status code, Request Headers, Request Body, Request Cookies, Response Headers, Response Body.

There is also the “Requirements” tab. When we have tests as part of our code base, all test results will be organized as associated with requirements.
There is also a “Features” tab. This page lists all the features that are part of your suite. If you expand that row you’ll see the bit of narrative text that is part of the current feature file.
Serenity-Summary.html

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
The complete code can be found on GitHub.