Allure Framework is a lightweight, flexible multi-language test report tool that not only displays a very concise representation of what has been tested in a neat web report form, but also allows everyone involved in the development process to extract the most useful information from everyday test execution.
Author: vibssingh
Difference between JUnit4 and JUnit5
In this article, we’ll see an overview of the differences between the two versions of the library.
Table of Contents
- Architecture
- JDK Version
- Imports
- Assertions
- Assumptions
- Conditional Test Execution
- Extending JUnit
- Non-public Test Methods are Allowed
- Repeat Tests
- Parameterized Tests
1. Architecture
JUnit 4 has everything bundled into a single jar file whereas JUnit 5 is composed of 3 sub-projects i.e. JUnit Platform, JUnit Jupiter, and JUnit Vintage.
JUnit4
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
JUnit Platform: It defines the TestEngine API for developing new testing frameworks that run on the platform.
JUnit Jupiter: It has all new JUnit annotations and TestEngine implementation to run tests written with these annotations.
JUnit Vintage: To support running JUnit 3 and JUnit 4 written tests on the JUnit 5 platform.
JUnit5
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.9.0-M1</version>
<scope>test</scope>
</dependency>
2. JDK Version
JUnit 4 requires Java 5 (or higher) whereas JUnit 5 requires Java 8 (or higher).
3. Imports
JUnit 5 uses the org.JUnit package for its annotations and classes whereas JUnit 5 uses the new org.JUnit.jupiter package for its annotations and classes. For example, org.JUnit.Test becomes org.JUnit.jupiter.api.Test.
@Before annotation of JUnit4 is renamed to @BeforeEach in JUnit5
@After annotation of JUnit4 is renamed to @AfterEach in JUnit5
@BeforeClass annotation of JUnit4 is renamed to @BeforeAll in JUnit5
@AfterClass annotation of JUnit4 is renamed to @AfterAll in JUnit5
4. Assertions
JUnit 5 assertions are now in org.JUnit.jupiter.api.Assertions whereas JUnit4 assertions are in org.JUnit.Assert. Most of the common assertions, like assertEquals() and assertNotNull() look the same as before, but there are a few key differences:
- The error message is now the last argument, for example, assertEquals(“my message”, 1, 2) would be assertEquals(1, 2, “my message”)
- Most assertions now accept a lambda that constructs the error message, which is only called when the assertion fails.
Below is an example of the same.
@Test
void nullNegative() {
String str = "Summer";
Assertions.assertNull(str, () -> "The string should be null");
}
The output of the above program is

- assertTimeout() and assertTimeoutPreemptively() have replaced the @Timeout annotation (note that there is a @Timeout annotation in JUnit 5, but it works differently than JUnit 4).
- There are several new assertions in JUnit5- assertAll(), assertIterableEquals(), assertLinesMatch(), assertThrows() and assertDoesNotThrow(). To know more about assertions in JUnit5, please refer to this tutorial – JUnit5 Assertions Example
5. Assumptions
In Junit 4, org.junit.Assume contains methods for stating assumptions about the conditions in which a test is meaningful. It has the following five methods:
- assumeFalse()
- assumeNoException()
- assumeNotNull()
- assumeThat()
- assumeTrue()
JUnit5 has the following three methods:
- assumeFalse()
- assumingThat()
- assumeTrue()
Below is an example of assumeThat() annotation in JUnit5.
@Test
void assumingThatTest() {
System.setProperty("ENV", "UAT");
assumingThat(
"UAT".equals(System.getProperty("ENV")),
() -> {
// Since the condition is true, this assertion will get executed
System.out.println("Assuming that executable executed");
assertEquals((num1+num2),num4,"The product of "+ num1 +" and "+ num2 +" is not equal to "+num4);
});
System.out.println("Loop outside");
assertEquals((num5-num2),num6,"The difference of "+ num5 +" and "+num2+" is not equal to " + num6);
}
The output of the above program is

6. Conditional Test Execution
In JUnit4, @Ignore is used to skip the execution of a test whereas @Disabled or one of the other built-in execution conditions is used to skip the execution of the test in JUnit5. To know more about skipping the tests in JUnit5, please refer to this tutorial – How to disable tests in JUnit5 – @Disabled.
Below is an example of @Disabled in JUnit5.
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.junit.jupiter.api.Assertions.*;
class DisabledTestsDemo {
WebDriver driver;
@BeforeEach
public void setUp() {
WebDriverManager.chromedriver().setup();
ChromeOptions chromeOptions = new ChromeOptions();
driver = new ChromeDriver(chromeOptions);
driver.manage().window().fullscreen();
driver.get("http://automationpractice.com/index.php");
}
@Disabled("This test is not applicable for Sprint 14")
@Test
void verifyPopularLink() {
boolean displayed = driver.findElement(By.xpath("//*[@id='home-page-tabs']/li[1]/a")).isDisplayed();
assertTrue(displayed);
}
@Test
void verifyContactNumber() {
String contactDetail = driver.findElement(By.xpath("//span[@class='shop-phone']/strong")).getText();
assertEquals("0123-456-789", contactDetail);
}
@Disabled("This test is blocked till bug 1290 is fixed")
@Test
void verifyWomenLink() {
boolean enabled = driver.findElement(By.xpath("//*[@id='block_top_menu']/ul/li[1]/a")).isEnabled();
assertTrue(enabled);
}
@AfterEach
public void tearDown() {
driver.close();
}
}
The output of the above program is

JUnit 5 provides the ExecutionCondition extension API to enable or disable a test or container (test class) conditionally. This is like using @Disabled on a test but it can define custom conditions. There are multiple built-in conditions, such as:
- @EnabledOnOs and @DisabledOnOs: Enables a test only on specified operating systems.
- @EnabledOnJre and @DisabledOnJre: Specifies the test should be enabled or disabled for specific versions of Java.
- @EnabledIfSystemProperty: Enables a test based on the value of a JVM system property.
- @EnabledIf: Uses scripted logic to enable a test if scripted conditions are met.
7. Extending JUnit
@RunWith no longer exists; superseded by @ExtendWith in JUnit5.
In JUnit 4, customizing the framework generally meant using a @RunWith annotation to specify a custom runner. Using multiple runners was problematic, and usually required chaining or using a @Rule. This has been simplified and improved in JUnit 5 using extensions.
import net.serenitybdd.core.Serenity;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import net.thucydides.core.annotations.Managed;
import net.thucydides.core.annotations.Steps;
import net.thucydides.core.annotations.Title;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.WebDriver;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SerenityJUnit5Extension.class)
class ApplicationLoginJUnit5Tests {
@Managed
WebDriver driver;
@Steps
NavigateAction navigateAction;
@Steps
StepLoginPage loginPage;
@Test
@Title("Login to application with valid credentials navigates to DashBoard page")
void successfulLogin() {
navigateAction.toTheHomePage();
// When
loginPage.inputUserName("Admin");
loginPage.inputPassword("admin123");
loginPage.clickLogin();
// Then
Serenity.reportThat("Passing valid credentials navigates to DashBoard page",
() -> assertThat(dashboardPage.getHeading()).isEqualToIgnoringCase("DashBoard"));
}
}
8. Non-public Test Methods are Allowed
JUnit 5 test classes and test methods are not required to be public. We can now make them package protected.
JUnit internally uses reflection to find test classes and test methods. Reflection can discover them even if they have limited visibility, so there is no need for them to be public.
9. Repeat Tests
JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with @RepeatedTest and specifying the total number of repetitions desired. To know more about RepestedTest, please refer to this tutorial – How to Retry Test in JUnit5 – @RepeatedTest
Below is the example of @RepeatedTest in JUnit5.
@RepeatedTest(3)
void repeatedTestWithRepetitionInfo1(RepetitionInfo repetitionInfo) {
assertEquals(3, repetitionInfo.getTotalRepetitions());
}
The output of the above program is

10. Parameterized Tests
Test parameterization existed in JUnit 4 with built-in libraries like JUnit4Parameterized or third-party libraries like JUnitParams. In JUnit 5, parameterized tests are completely built-in and adopt some of the best features from JUnit4Parameterized and JUnitParams. To know more about the parameterized tests in JUnit5, please refer to this tutorial – How to parameterized Tests in JUnit5.
Below is an example of parameterized Test in JUnit5.
public class CSVParameterizedTest {
@ParameterizedTest
@CsvSource({
"java, 4",
"javascript, 7",
"python, 6",
"HTML, 4",
})
void test(String str, int length) {
assertEquals(length, str.length());
}
}
The output of the above program is

Congratulations. We have gone through the differences between JUnit4 and JUnit5. Happy Learning!!
How to test DELETE Request Using Python Requests
In this tutorial, we will test DELETE Request in Python.
Prerequisite:
- Python is installed on the machine
- PIP is installed on the machine
- PyCharm or other Python Editor is installed on the machine
If you need help in installing Python, please refer to this tutorial – How to Install Python on Windows 11.
If you need help in installing PyCharms, please refer to this tutorial – How to install PyCharms on Windows 11.
Below is the example of DELETE Request.

Installation of Python Requests Module
Step 1 – If you are using PyCharm IDE then you need to install the Request library. Execute the below command using pip.
pip install -U requests
Step 2 – Install Pytest
pip install -U pytest
Step 3 – Create a new project folder and open it in PyCharm.

Step 4 – Go to the project folder and Create a new file, name it “DeleteRequest.py”.

Step 5 – Create the test
Import the required packages.
The DELETE method is typically used to request that a resource be removed or deleted.
import requests
ENDPOINT = 'https://reqres.in/api/users/2'
def test_delete_user():
response = requests.delete(ENDPOINT)
assert response.status_code == 204
requests.delete(url) – function sends a DELETE request to the specified URL.
The response object contains information about the response, including the status code and the response content.
The output of the above program is

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Allure Report with Cucumber, Selenium and TestNG
In the previous tutorial, I explained the Integration of the Allure Report with Selenium and TestNG. In this tutorial, I will explain how to Integrate Allure Report with Cucumber, Selenium, and TestNG.
The below example covers the implementation of Allure Reports with Cucumber, Selenium, TestNG, Java, and Maven. Before starting, make sure to install Allure on your machine. Refer to this tutorial to install allure – What is Allure Report?.
Project Structure

Table of Contents
- Prerequisite
- Dependency List
- Implementation Steps
- Update the Properties section in Maven pom.xml
- Add Cucumber5, Selenium, TestNG, Allure-Cucumber5, and Allure-TestNG dependencies
- Update the Build Section of pom.xml in the Allure Report Project
- Create a Feature file
- Create the Step Definition class or Glue Code
- Create a TestNG Cucumber Runner class
- Create testng.xml for the project
- Run the Test and Generate Allure Report
- Allure Report Dashboard
Prerequisite
- Java 17 installed
- Maven installed
- Eclipse or IntelliJ installed
- Allure installed
Dependency List
- Selenium – 4.16.1
- Java 17
- Cucumber – 7.15.0
- Maven – 3.9.6
- Allure Report – 2.25.0
- Allure Maven – 2.12.0
- Aspectj – 1.9.21
- Maven Compiler Plugin – 3.12.1
- Maven Surefire Plugin – 3.2.3
Implementation Steps
Step 1 – Update the Properties section in Maven pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>7.15.0</cucumber.version>
<selenium.version>4.16.1</selenium.version>
<testng.version>7.9.0</testng.version>
<maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
<maven.compiler.source.version>17</maven.compiler.source.version>
<maven.compiler.target.version>17</maven.compiler.target.version>
<allure.junit4.version>2.25.0</allure.junit4.version>
<aspectj.version>1.9.21</aspectj.version>
<allure.version>2.25.0</allure.version>
<allure.maven>2.12.0</allure.maven>
</properties>
Step 2 – Add dependencies to pom.xml
Add Cucumber, Selenium, TestNG, Allure-Cucumber, and Allure-TestNG dependencies to pom.xml (Maven Project).
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-bom</artifactId>
<version>${allure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- TestNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<!--Allure Cucumber Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber7-jvm</artifactId>
<scope>test</scope>
</dependency>
<!--Allure Reporting Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Step 3 – Update the Build Section of pom.xml in the Allure Report Project
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.maven}</version>
<configuration>
<reportVersion>${allure.maven}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
The complete pom.xml is
<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>com.example</groupId>
<artifactId>AllureReport_Cucumber_TestNG</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>AllureReport_Cucumber_TestNG</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>7.15.0</cucumber.version>
<selenium.version>4.16.1</selenium.version>
<testng.version>7.9.0</testng.version>
<maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
<maven.compiler.source.version>17</maven.compiler.source.version>
<maven.compiler.target.version>17</maven.compiler.target.version>
<allure.junit4.version>2.25.0</allure.junit4.version>
<aspectj.version>1.9.21</aspectj.version>
<allure.version>2.25.0</allure.version>
<allure.maven>2.12.0</allure.maven>
</properties>
<!-- Add allure-bom to dependency management to ensure correct versions of all the dependencies are used -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-bom</artifactId>
<version>${allure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- TestNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<!--Allure Cucumber Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber7-jvm</artifactId>
<scope>test</scope>
</dependency>
<!--Allure Reporting Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.maven}</version>
<configuration>
<reportVersion>${allure.maven}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 4 – Create a Feature file
Create a folder – features within src/test/resources to create test scenarios in the Feature file.

Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. In this feature file. The test scenarios are written in Gherkins language.
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login successfully and new page open
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
| 234 | xyz$$ | Invalid credentials! |
Step 5 – Create the Step Definition class or Glue Code
The stepdefinition class is created in src/test/java directory.

Below is the code for the Hooks.
package com.example.definitions;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.time.Duration;
public class Hooks {
protected static WebDriver driver;
public final static int TIMEOUT = 5;
@Before
public void setUp() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
}
@After
public void tearDown(Scenario scenario) {
try {
String screenshotName = scenario.getName();
if (scenario.isFailed()) {
TakesScreenshot ts = (TakesScreenshot) driver;
byte[] screenshot = ts.getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "img/png", screenshotName);
}
} catch (Exception e) {
e.printStackTrace();
}
driver.quit();
}
}
LoginPageDefinition
package com.example.definitions;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.openqa.selenium.By;
import org.testng.Assert;
public class LoginPageDefinitions {
Hooks hooks;
@Given("User is on HRMLogin page {string}")
public void loginTest(String url) {
hooks.driver.get(url);
}
@When("User enters username as {string} and password as {string}")
public void goToHomePage(String userName, String passWord) {
// login to application
hooks.driver.findElement(By.name("username")).sendKeys(userName);
hooks.driver.findElement(By.name("password")).sendKeys(passWord);
hooks.driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();
// go the next page
}
@Then("User should be able to login successfully and new page open")
public void verifyLogin() {
String homePageHeading = hooks.driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();
//Verify new page - HomePage
Assert.assertEquals(homePageHeading,"Dashboard");
}
@Then("User should be able to see error message {string}")
public void verifyErrorMessage(String expectedErrorMessage) {
String actualErrorMessage = hooks.driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
// Verify Error Message
Assert.assertEquals(actualErrorMessage, expectedErrorMessage);
}
}
Step 6 – Create a TestNG Cucumber Runner class
We need to create a class called Runner class to run the tests. This class will use the TestNG annotation @Test, which tells TestNG what is the test runner class.
package com.example.runner;
import org.testng.annotations.Test;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
@Test
@CucumberOptions(tags = "", features = {"src/test/resources/features"}, glue = {"com.example.definitions"},
plugin = {"pretty","io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"})
public class CucumberRunnerTests extends AbstractTestNGCucumberTests{
}
Note:- @Test annotation marks this class as part of the test. So, if we will remove this annotation, the Allure Report executes CucumberRunnerTests as a separate test suite, so there will be duplicate results.
Step 7 – Create testng.xml for the project
<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "Suite1">
<test name = "Test Demo">
<classes>
<class name = "com.example.runner.CucumberRunnerTests"/>
</classes>
</test>
</suite>
Step 8 – Run the Test and Generate Allure Report
To run the tests, use the below command
mvn clean test
In the below image, we can see that one test failed and four passed out of five tests.

This will create the allure-results folder with all the test reports within target folder. These files will be used to generate Allure Report.

Use the below command to generate the Allure Report
allure serve

This will generate the beautiful Allure Test Report as shown below.
Allure Report Dashboard

Categories in Allure Report
The categories tab gives you a way to create custom defect classifications to apply for test results. There are two categories of defects – Product Defects (failed tests) and Test Defects (broken tests).

Suites in Allure Report
On the Suites tab a standard structural representation of executed tests, grouped by suites and classes can be found. Here, we have 2 suits – Feature and Surefire test. Surefire tests are executed from CucumberRunnerTests.

Graphs in Allure Report
Graphs allow you to see different statistics collected from the test data: status breakdown or severity and duration diagrams.

Timeline in Allure Report
The timeline tab visualizes retrospective test execution, allure adaptors collect precise timings of tests, and here on this tab, they are arranged accordingly to their sequential or parallel timing structure.

Behaviours of Allure Report
This tab groups test results according to Epic, Feature, and Story tags.

Screenshot attached to the failed test case

Packages in Allure Report
The packages tab represents a tree-like layout of test results, grouped by different packages.

When we don’t use @Test in CucumberRunnerTests.java, then as mentioned above the Allure report will have duplicate details.
Congratulations!! We have integrated an allure report with Cucumber, Selenium, and TestNG. I hope this tutorial is useful to you.
Additional Tutorials on Allure Reports
Integration of Allure Report with Selenium and JUnit4
Integration of Allure Report with Selenium and TestNG
Gradle – Allure Report for Selenium and JUnit4
Gradle – Allure Report for Cucumber, Selenium and TestNG
Integration of Allure Report with Rest Assured and JUnit4
Difference between Static Method and Non-Static Method
Static Method
- Static method is a method that belongs to the class, not to the instance of the class.
- It can be access without creating the object of the class.
- Static method can only access static variables, static methods of same class or another class.
- Method Overriding – Static methods cannot be overridden because of early binding
- Memory Allocation – In static method, memory allocation happens only once, because the static keyword fixed a particular memory for that method in ram. So when the method calls every time in a program, each time that particular memory is used.
Below is an example that shows how the static methods can be use without creating an object of the class.
package com.example.definitions;
public class staticMyClass {
static void MyStatic_Method() { // Static Method
System.out.println("Static method can be accessed without creating object");
}
public void MyPublic_Method() { // Public Method
System.out.println("Public method can be accessed only by creating object");
}
public static void main(String[] args) {
MyStatic_Method(); // Calling Static Method
}
}
The output of the above program is

Non Static Method
- Non Static can be public, private, protected or default. They do not have static or non-static keyword before their method name.
- It can be access by creating the object of the class.
- Non Static method can access static variables, static methods of same class or another class as well as non-static variables and methods.
- Method Overriding – Non Static methods can be overridden because of runtime binding
- Memory Allocation – In non-static method, memory allocation happens when the method invokes and the memory is allocated every time when the method is called. So more memory is used here as compared to static method.
public class nonStaticClass {
static void MyStatic_Method() { // Static Method
System.out.println("Static method can be accessed without creating object");
}
public void MyPublic_Method() { // Public Method
System.out.println("Public method can be accessed only by creating object");
}
public static void main(String[] args) {
nonStaticClass stat = new nonStaticClass();
stat.MyPublic_Method(); // Calling Non Static Method
}
}
The output of the above program is

How to manage driver executables using WebDriverManager
The traditional way to use any browser in Selenium tests is to download browser binaries, and we need to set the path of these files in our script like below or its location should be added to the classpath.
System.setProperty("webdriver.chrome.driver", "/absolute/path/to/binary/chromedriver");
The process of manually downloading and managing these drivers for each of the operating systems is very painful. We also have to check when new versions of the binaries are released / new browser versions are released. We should check the compatibility for all the executables and add them.
Note: – Selenium 4.6 and above has inbuilt tool to handle drivers. If you are using Selenium version less than 4.6, then you can use WebDriverManager.
How to download all the driver executables automatically?
The automatic download of the drivers can be done by WebDriverManager. WebDriverManager is a library that allows controlling web browsers programmatically. It provides a cross-browser API that can be used to drive web browsers (e.g., Chrome, Edge, or Firefox, among others) using different programming languages (e.g., Java, JavaScript, Python, C#, or Ruby). The primary use of Selenium WebDriver is implementing automated tests for web applications.

The communication between the WebDriver API and the driver binary is done using a standard protocol called W3C WebDriver (formerly the so-called JSON Wire Protocol). Then, the communication between the driver and the browser is done using the native capabilities of each browser.
How To add WebDriverManager to a Selenium project manually?
Download the latest version of WebDriverManager from here.

It will download a zip file. Now extract the jar/zip file. It will show various .jar under the folder, as shown below:

Once we extract the zip file, we have to reference these jar files in our project. For this, navigate to project properties and click Build Path-> Configure Build Path in Eclipse

Click “Add External Jars” as per the steps highlighted below to include all the WebDriverManager jars extracted.
After clicking on the “Add External JARs“, all the selected extracted JARs are added to the project.
When this finishes, the project references show these referenced jars in the project explorer as highlighted below, and they are ready to be consumed in the Selenium test scripts.

Chrome
The below code snippet shows a quick usage of WebDriverManager with Chrome:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
public class Demo {
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
// Create an object of Chrome Options class
ChromeOptions chromeOptions = new ChromeOptions();
// Create an object of WebDriver class and pass the Chrome Options object as
// an argument
WebDriver driver = new ChromeDriver(chromeOptions);
System.out.println("Executing Chrome Driver");
driver.get("https://www.bing.com/");
System.out.println("Title of Page :" + driver.getTitle());
System.out.println("Page URL : " + driver.getCurrentUrl());
// Close the driver
driver.close();
}
}
The output of the above program is

FireFox Driver
The below code snippet shows a quick usage of WebDriverManager with FireFox:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
public class FireFoxDemo {
public static void main(String[] args) {
WebDriverManager.firefoxdriver().setup();
// Create an object of Firefox Options class
FirefoxOptions firefoxOptions = new FirefoxOptions();
// Create an object of WebDriver class and pass the Firefox Options object
// as an argument
WebDriver driver = new FirefoxDriver(firefoxOptions);
System.out.println("Executing Firefox Driver");
driver.get("https://www.bing.com/");
System.out.println("Title of Page :" + driver.getTitle());
System.out.println("Page URL : " + driver.getCurrentUrl());
// Close the driver
driver.close();
}
}
The output of the above program is

Microsoft Edge
The below code snippet shows a quick usage of WebDriverManager with Microsoft Edge:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
public class EdgeDemo {
public static void main(String[] args) {
WebDriverManager.edgedriver().setup();
// Create an object of Edge Options class
EdgeOptions edgeOptions = new EdgeOptions();
// Create an object of WebDriver class and pass the Edge Options object
// as an argument
WebDriver driver = new EdgeDriver(edgeOptions);
System.out.println("Executing Microsoft Edge Driver");
driver.get("https://www.bing.com/");
System.out.println("Title of Page :" + driver.getTitle());
System.out.println("Page URL : " + driver.getCurrentUrl());
// Close the driver
driver.close();
}
}
The output of the above program is

The basic use of these managers is the following:
WebDriverManager.chromedriver().setup();
WebDriverManager.firefoxdriver().setup();
WebDriverManager.edgedriver().setup();
WebDriverManager.operadriver().setup();
WebDriverManager.chromiumdriver().setup()
WebDriverManager.iedriver().setup();
How To add WebDriverManager to a Selenium project using Maven or Gradle?
To use WebDriverManager in a Maven built project, the below-mentioned dependency is needed to add to the pom.xml.
<!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.1.0</version>
</dependency>
For Gradle project, add the below to the build.gradle.
dependencies {
testCompile("io.github.bonigarcia:webdrivermanager:5.1.0")
}
How to instantiate a specific browser version using WebDriverManager?
WebDriverManager provides the ability to download a specific version of the browser. For example, the latest chromedriver version is 100.0.4896.20 (released on 2022-03-04). But if we want an earlier version, say, Chromedriver version 98.0.4758.102, we have to add the following code.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
public class Demo {
public static void main(String[] args) {
WebDriverManager.chromedriver().driverVersion("98.0.4758.102").setup();
// Create an object of Chrome Options class
ChromeOptions chromeOptions = new ChromeOptions();
// Create an object of WebDriver class and pass the Chrome Options object as
// an argument
WebDriver driver = new ChromeDriver(chromeOptions);
System.out.println("Executing Chrome Driver");
driver.get("https://www.bing.com/");
System.out.println("Title of Page :" + driver.getTitle());
System.out.println("Page URL : " + driver.getCurrentUrl());
// Close the driver
driver.close();
}
}
The output of the above program is

As we can see from the above screenshot, as a result of executing the above program, the Chromedriver started successfully. We can see the details of starting the chrome driver instance in the first line of output. Here we have set the Chrome version to “98.0.4758.102″.
Congratulations!! We have learned to download drivers automatically.
How to test PUT Request Using Python Requests
In this tutorial, we will test PUT Request in Python.
Prerequisite:
- Python is installed on the machine
- PIP is installed on the machine
- PyCharm or other Python Editor is installed on the machine
If you need help in installing Python, please refer to this tutorial – How to Install Python on Windows 11.
If you need help in installing PyCharms, please refer to this tutorial – How to install PyCharms on Windows 11.
Below is the example of PUT Request.

Installation of Python Requests Module
Step 1 – If you are using PyCharm IDE then you need to install the Request library. Execute the below command using pip.
pip install -U requests
Step 2 – Install Pytest
pip install -U pytest
Step 3 – Create a new project folder and open it in PyCharm.

Step 4 – Go to the project folder and Create a new file, name it “PuttRequest.py”.

Step 5 – Create the test
Import the required packages.
The PUT method is typically used to update or create a resource on the server and returns 200 for successful call.
import requests
ENDPOINT = 'https://reqres.in/api/users/2'
def test_update_user():
request_body = {
"name": "Vibha",
"Job": "CTO"
}
response = requests.put(ENDPOINT, request_body)
response_body = response.json()
print(response_body)
assert response.status_code == 200
assert response_body["Job"] == "CTO"
requests.put(url, data=data) – function sends a PUT request to the specified URL with the provided data. The data dictionary contains the key-value pairs that we want to send in the PUT request payload. You can modify it based on the requirements of the API we are working with.
The response object contains information about the response, including the status code and the response content.
The output of the above program is

The complete code can be found in GitHub – vibssingh/RestAPITesting_Python
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Requests in Python
Requests is an HTTP client library for the Python programming language. Requests is one of the most downloaded Python libraries, with over 300 million monthly downloads. It maps the HTTP protocol onto Python’s object-oriented semantics.
| Chapter 1 How to test GET Request Using Python Requests |
| Chapter 2 How to test POST Request Using Python Requests |
| Chapter 3 How to test PUT Request Using Python Requests |
| Chapter 4 How to test DELETE Request Using Python Requests |
| Chapter 5 How to test PATCH Request Using Python Requests |
| Chapter 6 How to add header to Python Requests |
| Chapter 7 How to test response time in Request Using Python Requests |
| Chapter 8 How to pass basic authentication credentials in Python Requests |
| Chapter 9 How to pass basic authentication token in Python Requests – NEW |
| Chapter 10 How to create Python Allure Report for Rest API – NEW |
| Chapter 11 How to add environment details to Python Allure Report – NEW |
| Chapter 12 How to run Python Rest API tests with GitHub Actions – NEW |
| Chapter 13 Status Code, Line, Body, and Header Verification in Python Requests – NEW |
How to test POST Request Using Python Requests
In this tutorial, we will test POST Request in Python using Requests.
Prerequisite:
- Python is installed on the machine
- PIP is installed on the machine
- PyCharm or other Python Editor is installed on the machine
If you need help in installing Python, please refer to this tutorial – How to Install Python on Windows 11.
If you need help in installing PyCharms, please refer to this tutorial – How to install PyCharms on Windows 11.
Below is the example of POST Request.

Installation of Python Requests Module
Step 1 – If you are using PyCharm IDE then you need to install the Request library. Execute the below command using pip.
pip install -U requests
Step 2 – Install Pytest
pip install -U pytest
Step 3 – Create a new project folder and open it in PyCharm.

Step 4 – Go to the project folder and Create a new file, name it “PostRequest.py”.

Step 5 – Create the test
Import the required packages.
The POST method is used to get the resource from the server and returns 201 for successful call.
import requests
ENDPOINT = 'https://reqres.in/api/users'
def test_create_user():
response = requests.post(ENDPOINT, {"name": "Vibha", "job": "CTO"})
response_body = response.json()
print(response_body)
assert response.status_code == 201
assert response_body["name"] == "Vibha"
assert response_body["job"] == "CTO"
requests.post(url, data=data) – function sends a POST request to the specified URL with the provided data. The data dictionary contains the key-value pairs that we want to send in the POST request payload. You can modify it based on the requirements of the API we are working with.
The response object contains information about the response, including the status code and the response content.
The output of the above program is

In the above example, we have passed the request body in the requests.post(). In the below example, will define a variable and assign the request body to it.
def test_create_user1():
payload = {
"name": "Vibha",
"job": "CTO"
}
response = requests.post(ENDPOINT, payload)
response_body = response.json()
print(response_body)
assert response.status_code == 201
assert response_body["name"] == "Vibha"
assert response_body["job"] == "CTO"
The output of the above program is

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Allure Report with Cucumber, Selenium and JUnit4
In the previous tutorial, I have explained the Integration of the Allure Report with Selenium and JUnit4. In this tutorial, I will explain how to Integrate Allure Report with Cucumber7 and JUnit4.
Below example covers the implementation of Allure Reports in Selenium using JUnit4, Java and Maven.
Table of Contents
- Prerequisite
- Dependency List
- Project Structure
- Implementation Steps
- Update Properties section in Maven pom.xml
- Add dependencies to POM.xml
- Update Build Section of pom.xml in Allure Report Project
- Create Feature file in src/test/resources
- Create the Step Definition class or Glue Code
- Create a Cucumber Runner class
- Create allure.properties in src/test/resources
- Run the Test and Generate Allure Report
- Generate Allure Report
Prerequisite
- Java 11 or above installed
- Maven installed
- Eclipse or IntelliJ installed
- Allure installed and configured
Dependency List:
- Selenium – 4.16.1
- Java 17
- Cucumber – 7.15.0
- Maven – 3.9.5
- Allure BOM – 2.25.0
- Aspectj – 1.9.21
- Allure Maven – 2.12.0
- JUnit – 4.13.2
Project Structure

Implementation Steps
Step 1 – Update Properties section in Maven pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>7.15.0</cucumber.version>
<selenium.version>4.16.1</selenium.version>
<junit.version>4.13.2</junit.version>
<maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
<maven.compiler.source.version>17</maven.compiler.source.version>
<maven.compiler.target.version>17</maven.compiler.target.version>
<allure.junit4.version>2.25.0</allure.junit4.version>
<aspectj.version>1.9.21</aspectj.version>
<allure.version>2.25.0</allure.version>
<allure.maven>2.12.0</allure.maven>
</properties>
Step 2 – Add dependencies to POM.xml
Add Cucumber5, Selenium, JUnit4, Allure-Cucumber5 and Allure-JUnit4 dependencies in POM.xml
<dependencies>
<!--Cucumber Dependencies-->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!--Selenium Dependency-->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!--Hamcrest Dependency-->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<!--Allure Cucumber Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber5-jvm</artifactId>
<version>${allure.cucumber5.version}</version>
</dependency>
<!--Allure Reporting Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit4</artifactId>
<version>${allure.junit4.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Step 3 – Update Build Section of pom.xml in Allure Report Project
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.maven}</version>
<configuration>
<reportVersion>${allure.maven}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
The complete pom.xml is 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>com.example</groupId>
<artifactId>AllureReport_Cucumber_JUnit4</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>AllureReport_Cucumber_JUnit4</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>7.15.0</cucumber.version>
<selenium.version>4.16.1</selenium.version>
<junit.version>4.13.2</junit.version>
<maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
<maven.compiler.source.version>17</maven.compiler.source.version>
<maven.compiler.target.version>17</maven.compiler.target.version>
<allure.junit4.version>2.25.0</allure.junit4.version>
<aspectj.version>1.9.21</aspectj.version>
<allure.version>2.25.0</allure.version>
<allure.maven>2.12.0</allure.maven>
</properties>
<!-- Add allure-bom to dependency management to ensure correct versions of all the dependencies are used -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-bom</artifactId>
<version>${allure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- JUnit4 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--Allure Cucumber Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber7-jvm</artifactId>
<scope>test</scope>
</dependency>
<!--Allure Reporting Dependency-->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit4</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>${allure.maven}</version>
<configuration>
<reportVersion>${allure.maven}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 4 – Create Feature file in src/test/resources

Create source folder – src/test/resources and features folder within src/test/resources to create test scenarios in Feature file. Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. In this feature file, I have created a scenario for successful login and one Scenario Outline for failed login. The test scenarios are written in Gherkins language.
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login successfully and new page open
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
| 234 | xyz$$ | Invalid credentials! |
Step 5 – Create the Step Definition class or Glue Code
The stepdefinition class is created in src/test/java.
Below is the code for the LoginDefinition class.
package com.example.definitions;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
public class LoginPageDefinitions {
Hooks hooks;
@Given("User is on HRMLogin page {string}")
public void loginTest(String url) {
hooks.driver.get(url);
}
@When("User enters username as {string} and password as {string}")
public void goToHomePage(String userName, String passWord) {
// login to application
hooks.driver.findElement(By.name("username")).sendKeys(userName);
hooks.driver.findElement(By.name("password")).sendKeys(passWord);
hooks.driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();
// go the next page
}
@Then("User should be able to login successfully and new page open")
public void verifyLogin() {
String homePageHeading = hooks.driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();
//Verify new page - HomePage
Assert.assertEquals("Dashboard",homePageHeading);
}
@Then("User should be able to see error message {string}")
public void verifyErrorMessage(String expectedErrorMessage) {
String actualErrorMessage = hooks.driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
// Verify Error Message
Assert.assertEquals(expectedErrorMessage,actualErrorMessage);
}
}
Hook.java
package com.example.definitions;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.time.Duration;
public class Hooks {
protected static WebDriver driver;
public final static int TIMEOUT = 5;
@Before
public void setUp() {
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
}
@After
public void tearDown(Scenario scenario) {
try {
String screenshotName = scenario.getName();
if (scenario.isFailed()) {
TakesScreenshot ts = (TakesScreenshot) driver;
byte[] screenshot = ts.getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "img/png", screenshotName);
}
} catch (Exception e) {
e.printStackTrace();
}
driver.quit();
}
}
Step 6 – Create a Cucumber Runner class
We need to create a class called Runner class to run the tests. This class will use the JUnit annotation @RunWith(), which tells JUnit what is the test runner class.
package com.example.runner;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
@RunWith(Cucumber.class)
@CucumberOptions(tags = "", features = {"src/test/resources/features"}, glue = {"com.example.definitions"},
plugin = {"pretty","io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"})
public class CucumberRunnerTests {
}
Step 7 – Create allure.properties in src/test/resources
Allure, by default, saves test results in the project’s root directory. However, it is recommended to store your test results in the build output directory. To configure this, create an allure.properties file and place it in the test resources directory of your project, which is typically located at src/test/resources:
allure.results.directory=target/allure-results
Step 8 – Run the Test and Generate Allure Report
To run the tests, use the below command
mvn clean test
In the below image, we can see that one test is failed and four passed out of five tests.

This will create allure-results folder with all the test report. These files will be use to generate Allure Report.

Step 9 – Generate Allure Report
Change current directory to target directory and then use the below command to generate the Allure Report
allure serve
This will generate the beautiful Allure Test Report as shown below.
Allure Report Dashboard

It shows detail of all the test steps and the screenshot of the failed test step also as shown below.


Categories in Allure Report
Categories tab gives you the way to create custom defects classification to apply for test results. There are two categories of defects – Product Defects (failed tests) and Test Defects (broken tests).

Suites in Allure Report
On the Suites tab a standard structural representation of executed tests, grouped by suites and classes can be found.

Graphs in Allure Report
Graphs allow you to see different statistics collected from the test data: statuses breakdown or severity and duration diagrams.

Timeline in Allure Report
Timeline tab visualizes retrospective of tests execution, allure adaptors collect precise timings of tests, and here on this tab they are arranged accordingly to their sequential or parallel timing structure.

Behaviors of Allure Report
This tab groups test results according to Epic, Feature and Story tags.

Packages in Allure Report
Packages tab represents a tree-like layout of test results, grouped by different packages.

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
The complete code can be found on GitHub – vibssingh/AllureReport_Cucumber_JUnit4.