In the previous tutorial, I have explained the Serenity BDD with Cucumber for Web Application using Junit4. In this tutorial, I will explain the same Test Framework using Serenity, Cucumber and JUnit5. This tutorial gives a clear picture for the initial setup of a BDD Framework .
What is JUnit5?
JUnit 5 is composed of several different modules from three different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also defines the TestEngine API for developing a testing framework that runs on the platform.
JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a TestEngine for running Jupiter based tests on the platform.
JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests on the platform. It requires JUnit 4.12 or later to be present on the class/module path.
JUnit5 is not completely integrated with Serenity with Cucumber. So, it is advisable to use jupiter-vintage-engine for the Cucumber TestRunner classes.
This framework consists of:
- Serenity – 3.2.3
- Serenity Cucumber – 3.2.3
- JUnit Jupiter – 5.8.0
- JUnit Vintage – 5.8.0
- Java 11
- Maven – 3.8.1
- Selenium – 3.141.59
- Maven Compiler Plugin – 3.8.1
- Maven Surefire Plugin – 3.0.0-M5
- Maven FailSafe Plugin – 3.0.0-M5
Implementation Steps
- Download and Install Java on system
- Download and setup Eclipse IDE on system
- Setup Maven and create a new Maven Project
- Update Properties section in Maven pom.xml
- Add repositories and pluginRepository to Maven pom.xml
- Add Serenity, Serenity Cucumber and JUnit5 dependencies to POM.xml
- Update Build Section of pom.xml
- Create a feature file under src/test/resources
- Create cucumber.properties file under src/test/resources (optional)
- Create the Step Definition class or Glue Code
- Create a Serenity-Cucumber Runner class
- Create serenity.conf file under src/test/resources
- Create serenity.properties file in the root of the project
- Run the tests from Command Line
- Test Execution Status
- Serenity Report Generation – Index.html and Serenity-Summary.html
- Cucumber Report Generation (Optional)
Step 1- Download and Install Java
Click here to know How to install Java.
Step 2 – Download and setup Eclipse IDE on system
The Eclipse IDE (integrated development environment) provides strong support for Java developers which is needed to write Java code. Click here to know How to install Eclipse.
Step 3 – Setup Maven and create a new Maven Project
Click here to know How to install Maven.
Click here to know How to create a Maven project
Below is the Maven project structure. Here,
Group Id – com.example
Artifact Id – SerenityCucumberJunit5Demo
Version – 0.0.1-SNAPSHOT
Package – com. example. SerenityCucumberJunit5Demo

Step 4 – Update Properties section in Maven pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<serenity.version>3.2.3</serenity.version>
<serenity.cucumber.version>3.2.3</serenity.cucumber.version>
<junit.jupiter.version>5.8.0</junit.jupiter.version>
<junit.vintage.version>5.8.0</junit.vintage.version>
<maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.0.0-M5</maven.failsafe.plugin.version>
</properties>
Step 5 – Add repositories and pluginRepository to Maven pom.xml
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>bintray</name>
<url>https://jcenter.bintray.com</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>bintray-plugins</name>
<url>https://jcenter.bintray.com</url>
</pluginRepository>
</pluginRepositories>
Step 6 – Add Serenity, Serenity Cucumber, and JUnit dependencies to POM.xml
<dependencies>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.vintage.version}</version>
<scope>test</scope>
</dependency>
<!-- Serenity -->
<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-screenplay-webdriver</artifactId>
<version>${serenity.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Step 7 – 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>
<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 8 – Create a feature file under src/test/resources
The purpose of the Feature keyword is to provide a high-level description of a software feature, and to group related scenarios. To know more about the Feature file, please refer this tutorial.
Feature: Login to HRM
@ValidCredentials
Scenario: Login with valid credentials
Given User is on Home page
When User enters username as "Admin"
And User enters password as "admin123"
Then User should be able to login successfully
@InValidCredentials
Scenario Outline: Login with invalid credentials
Given User is on Home page
When User enters username as '<username>'
And User enters password as '<password>'
Then User should be able to see error message '<errorMessage>'
Examples:
|username |password |errorMessage |
|admin |admin |Invalid credentials |
|abc |admin123 |Invalid credentials |
|abc |abc123 |Invalid credentials |
|1$£" | 45£"% |Invalid credentials |
@ForgetPassword
Scenario: Verify Forget Password Functionality
Given User is on Home page
When User clicks on Forgot your password link
Then User should be able to see new page which contains Reset Password button
Step 9 – Create cucumber.properties file under src/test/resources (optional)
This is an optional step. Cucumber of version 6.7 and above provides the functionality to generate a beautiful cucumber report. For this, it is needed to add a file cucumber.properties under src/test/resources.
cucumber.publish.enabled = true
Step 10 – Create the Step Definition class or Glue Code
A Step Definition is a Java method with an expression that links it to one or more Gherkin steps. When Cucumber executes a Gherkin step in a scenario, it will look for a matching step definition to execute. You can have all of your step definitions in one file, or in multiple files.
LoginPageDefinitions
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.example.SerenityCucumberJunit5Demo.steps.StepDashboardPage;
import com.example.SerenityCucumberJunit5Demo.steps.StepForgetPasswordPage;
import com.example.SerenityCucumberJunit5Demo.steps.StepLoginPage;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import net.thucydides.core.annotations.Steps;
public class LoginPageDefinitions {
@Steps
StepLoginPage loginPage;
@Steps
StepDashboardPage dashPage;
@Steps
StepForgetPasswordPage forgetpasswordPage;
@Given("User is on Home page")
public void openApplication() {
loginPage.open();
}
@When("User enters username as {string}")
public void enterUsername(String userName) {
loginPage.inputUserName(userName);
}
@When("User enters password as {string}")
public void enterPassword(String passWord) {
loginPage.inputPassword(passWord);
loginPage.clickLogin();
}
@Then("User should be able to login successfully")
public void clickOnLoginButton() {
dashPage.loginVerify();
}
@Then("User should be able to see error message {string}")
public void unsucessfulLogin(String expectedErrorMessage) {
String actualErrorMessage = loginPage.errorMessage();
System.out.println("Actual Error Message :" + actualErrorMessage);
assertEquals(expectedErrorMessage, actualErrorMessage);
}
@When("User clicks on Forgot your password link")
public void clickForgetPasswordLink() {
loginPage.clickForgetPasswordLink();
}
@Then("User should be able to see new page which contains Reset Password button")
public void verifyForgetPasswordPage() {
assertTrue(forgetpasswordPage.ForgetPasswordPage());
}
}
Assertions in JUnit-Vintage Engine are imported from the below package:-
import static org.junit.jupiter.api.Assertions.*;
DashboardPageDefinitions
import com.example.SerenityCucumberJunit5Demo.steps.StepDashboardPage;
import net.thucydides.core.annotations.Step;
import net.thucydides.core.annotations.Steps;
public class DashboardPageDefinitions {
@Steps
StepDashboardPage dashPage;
@Step
public void verifyAdminLogin() {
dashPage.loginVerify();
}
}
The corresponding Test Step classes are – StepLoginPage and StepDashboardPage.
There are multiple ways to identify a web element on the web page – one of the ways is to use @FindBy or $(By.).
I prefer to use @FindBy as I need not find the same element multiple times. Using @FindBy, I have identified a web element and defined a WebElementFacacde for the same which is reusable.
StepLoginPage
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;
import net.thucydides.core.annotations.Step;
public class StepLoginPage extends PageObject {
@FindBy(name = "username")
WebElementFacade username;
@FindBy(name = "password")
WebElementFacade password;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
WebElementFacade submitButton;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
WebElementFacade errorMessage;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[4]/p")
WebElementFacade linkText;
@Step("Enter Username")
public void inputUserName(String userName) {
username.sendKeys((userName));
}
@Step("Enter Password")
public void inputPassword(String passWord) {
password.sendKeys((passWord));
}
@Step("Click Submit Button")
public void clickLogin() {
submitButton.click();
}
@Step("Error Message on unsuccessful login")
public String errorMessage() {
String actualErrorMessage = errorMessage.getText();
System.out.println("Actual Error Message :" + actualErrorMessage);
return actualErrorMessage;
}
@Step("Click Forget Password Link")
public void clickForgetPasswordLink() {
linkText.click();
System.out.println("Clicked on Forgot Password Link");
}
}
StepDashboardPage
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;
import net.thucydides.core.annotations.Step;
public class StepDashboardPage extends PageObject {
@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6")
WebElementFacade dashboardText;
@Step("Successful login")
public void loginVerify() {
String dashboardTitle = dashboardText.getText();
assertThat(dashboardTitle, containsString("Dashboard"));
}
}
StepForgetPasswordPage
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;
import net.thucydides.core.annotations.Step;
public class StepForgetPasswordPage extends PageObject {
@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/div/form/h6")
WebElementFacade forgetLink;
@Step("Verify Forget Password Page ")
public boolean ForgetPasswordPage() {
Boolean resetPasswordButton = forgetLink.isDisplayed();
return resetPasswordButton;
}
}
Step 11 – Create a Serenity-Cucumber Runner class
Cucumber runs the feature files via JUnit and needs a dedicated test runner class to actually run the feature files. When you run the tests with Serenity, you use the CucumberWithSerenity test runner. You also need to use the @CucumberOptions class to provide the root directory where the feature files can be found.
import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(plugin = {}, features = "src/test/resources/features/LoginPage.feature", glue = "com.example.SerenityCucumberJunit5Demo.definitions")
public class SerenityRunnerTest {
}
Step 12 – Create serenity.conf file under src/test/resources
The serenity configuration file is used to configure the drivers so the test cases can run successfully. This file contains an operating system-specific binary. The binary file sits between your test and the browser. It acts as an intermediary, an interface between your tests and the browser you are using.
You can also configure the webdriver.base.url property for different environments in the serenity.conf configuration file.
webdriver {
driver = firefox
}
#
# Define drivers for different platforms. Serenity will automatically pick the correct driver for the current platform
#
environments {
default {
webdriver.base.url = "https://opensource-demo.orangehrmlive.com/"
}
dev {
webdriver.base.url = "https://opensource-demo.orangehrmlive.com/dev"
}
staging {
webdriver.base.url = "https://opensource-demo.orangehrmlive.com/staging"
}
prod {
webdriver.base.url = "https://opensource-demo.orangehrmlive.com/prod"
}
}
Step 13 – Create serenity.properties file at the root of the project
serenity.project.name = Serenity and Cucumber and JUnit5 Demo
Step 14 – Run the tests from Command Line
Open the command line and go to the location where pom.xml of the project is present and type the below command.
mvn clean verify
Step 15 – Test Execution Status

The image displayed above shows the execution status.
The feature file contains 3 test cases. Test Case 2 is a Test Scenario that has 4 examples. So, in total we have 6 tests. This information is clearly mentioned in the new version of Serenity.
Step 16 – Serenity Report Generation
The best part about Serenity is the report generation by it. The Reports contain all possible types of information, you can think of with minimal extra effort. There are multiple types of reports are generated. We are interested in index.html and serenity-summary.html. To know more about Serenity Reports, please refer to tutorials for Index.html and Serenity-Summary.html. Below is the new Serenity Report.
- index.html


2. serenity-summary.html

Step 17 – Cucumber Report Generation (Optional)

Every Test Execution generates a Cucumber Report (Version 6.7.0) and above as shown in the image.
Copy the URL and paste it to a browser and it shows the report as shown below:

To know more about Cucumber Reports, refer this tutorial.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!