Testing of Gradle SpringBoot Application with Serenity, Cucumber and JUnit4

HOME

In the previous tutorial, I explained about Integration Testing of Springboot with Cucumber and TestNG. In this tutorial, I will explain the Testing of the Gradle SpringBoot Application with Serenity, Cucumber, and JUnit4.

Prerequisite:

Spring Boot 3.0.4 requires Java 17 and is compatible with and including Java 19. Spring Framework 6.0.6 or above is also required.

Explicit build support is provided for the following build tools:

  1. Maven – 3.5+
  2. Gradle – 7.x (7.5 or later) and 8.x

This framework consists of

  1. SpringBoot Starter Parent – 3.1.0
  2. Serenity –  3.6.12
  3. Serenity Cucumber – 3.6.12
  4. Serenity JUnit4 – 3.6.12
  5. Serenity Rest Assured – 3.6.12
  6. Spring
  7. Java 17
  8. Gradle – 7.6.1

What is SpringBoot Application?

 Spring Boot is an open-source micro-framework that provides Java developers with a platform to get started with an auto-configurable production-grade Spring application. 

  • Comes with embedded HTTP servers like Tomcat or Jetty to test web applications.
  • Adds many plugins that developers can use to work with embedded and in-memory databases easily. Spring allows you to easily connect with database and queue services like Oracle, PostgreSQL, MySQL, MongoDB, Redis, Solr, ElasticSearch, Rabbit MQ, and others.

What is RestController?

HTTP requests are handled by a controller in Spring’s approach to building RESTful web services. The @RestController annotation identifies these components, and the HelloController shown below (from src/main/java/com/example/springboot_demo/HelloController.java) handles GET requests for / and /qaautomation by returning a new instance of the Greeting class. Spring RestController takes care of mapping request data to the request-defined handles method.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class HelloController {
     
    @GetMapping(path="/")
    String hello() {
        return "Hello World, Spring Boot!";
    }
     
     
    @GetMapping(path="/qaautomation")
    String qaautomation() {
        return "Hello QA Automation!";
    }
 
}

Project Directory Structure

Implementation Steps

  1. Create a source folder – src/test/resources to create properties file
  2. Add SpringBootTest, Rest Assured, and JUnit4 dependencies to the project
  3. Create a feature file in src/test/resources
  4. Create the StepDefinition and Helper classes.
  5. Create a Serenity Runner class in the src/test/java directory
  6. Create an application.properties file in src/test/resources
  7. Create a serenity.properties at the root level of the project
  8. Run the tests from Command Line
  9. Serenity Report Generation
  10. Cucumber Report Generation

Step 1 – Create a source folder – src/test/resources to create test scenarios in the Feature file

Right-click on the test directory and select New->Directory and select resources (Maven Source Directories).

Step 2 – Add SpringBootTest, Rest Assured, and other dependencies to the project

We have added SpringBootTest, SpringBoot Web, Tomcat, Spring Web, Rest Assured, and JUnit4 dependencies to the build.gradle.

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.0-SNAPSHOT'
	id 'io.spring.dependency-management' version '1.1.0'
	id "net.serenity-bdd.serenity-gradle-plugin" version "3.6.7"
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }
	maven { url 'https://repo.spring.io/snapshot' }
}


dependencies {

	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-tomcat'
	implementation 'org.springframework:spring-web'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'net.serenity-bdd:serenity-core:3.6.12'
	testImplementation 'net.serenity-bdd:serenity-cucumber:3.6.12'
	testImplementation 'net.serenity-bdd:serenity-rest-assured:3.6.12'
	testImplementation 'net.serenity-bdd:serenity-spring:3.6.12'
	testImplementation 'net.serenity-bdd:serenity-junit:3.6.12'
	testImplementation 'org.junit.vintage:junit-vintage-engine'

}

tasks.named('test') {
	useJUnit() {}
	testLogging {
		showStandardStreams = true
	}
	systemProperties System.getProperties()
}

gradle.startParameter.continueOnFailure = true

test.finalizedBy(aggregate)

Step 3 – Create a feature file in src/test/resources

Below is an example of a feature file that shows a sample test scenario. Feature file should end with .feature. It contains the test scenarios in the form of simple English using the terms Given, When, Then, And.

Feature: SpringBoot Request
   
@ReceiveCorrectResponse

   Scenario Outline: Send a valid Request to get correct response
    Given I send a request to the URL "<url>"
    Then the response will return "<response>"

   Examples:
   | url             | response                   |
   | /               | Hello World, Spring Boot!  |
   | /qaautomation   | Hello QA Automation!       |

Step 4 – Create the StepDefinition and Helper classes.

Below is the code of the StepDefinition and Helper class. These classes are created in the src/test/java directory.

  • uses @SpringBootTest annotation which loads the actual application context.
  • uses WebEnvironment.RANDOM_PORT to create and run the application at some random server port.
  • @LocalServerPort gets the reference of the port where the server has started. It helps in building the actual request URIs to mimic real client interactions.

AbstractRestAssuredHelper

import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import net.serenitybdd.rest.SerenityRest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;


@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class AbstractRestAssuredHelper {
     private final static String BASE_URI = "http://localhost";
 
     @LocalServerPort
     private int port;

     @Value("${server.servlet.context-path}")
     private String basePath;
 
     protected void configureRestAssured() {
           RestAssured.baseURI = BASE_URI;
           RestAssured.port = port;
           RestAssured.basePath = basePath;
           
 
     }

     protected RequestSpecification getAnonymousRequest() {
           configureRestAssured();
           return SerenityRest.given();
     }
}

This class sends the request and receives a response after performing the GET operation. Here, the validation of the response also takes place by asserting the expected and actual response

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import net.thucydides.core.annotations.Steps;
import org.junit.Assert;

public class SpringBootDemoDefinitions {

	@Steps
    AbstractRestAssuredHelper helper;
    private Response response;

    @Given("I send a request to the URL {string}")
    public void iSendARequest(String endpoint) throws Exception  {
         response = helper.getAnonymousRequest()
                    .header("Content-Type", "application/json").when().get(endpoint);
    }

    @Then("the response will return {string}")
    public void extractResponse(String Expected ) {
          SerenityRest.restAssuredThat(response -> response.statusCode(200));
          String Actual = response.asString();    
          System.out.println("Result :"+Actual);
          Assert.assertEquals(Expected, Actual);
    }
}

Step 5 – Create a Serenity Runner class in the src/test/java directory

We cannot run a Feature file on its own in cucumber-based framework. We need to create a Java class that will run the Feature File. It is the starting point for JUnit to start executing the tests. TestRunner class is created under src/test/javaWhen you run the tests with serenity, you use the CucumberWithSerenity test runner.

import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;

@RunWith(CucumberWithSerenity.class)
@CucumberOptions(features = "src/test/resources/features", tags = "", glue = "com.example.Gradle_SpringBoot_Demo", publish = true)

public class SpringRunnerTests {

}

Step 6 – Create an application.properties file in src/test/resources

Application.properties is created under src/test/java

spring.profiles.active=dev
server.port=9091
server.servlet.context-path=/demo

spring.profiles.active – property to specify which profiles are active. The default profile is always active.
server.port – By default, the embedded server starts on port 8080. Now the server will start on port 8090
server.servlet.context-path – the context path in Spring Boot can be changed by setting a property, server.servlet.context-path.

Step 7 – Create a serenity.properties at the root level of the project

serenity.project.name = Testing of Gradle SpringBoot Application with Serenity and JUnit4 Demo

Step 8 – Run the tests from Command Line

Run the tests from the command line by using the below command

gradle clean test

The output of the above program is

This image shows that the profile name is “dev”. Application is started on port – “54462” and the context path is “/demo”.

Step 9 – Serenity Report Generation

By default, the test report generated by Serenity is placed under target/site/serenity/index.html. Below is the sample Serenity Report.

Below is the sample Serenity Report.

Step 10 – Cucumber Report Generation

A Cucumber Report can be generated by adding publish=true in SpringRunnerTests as shown in the above example. Click on the link provided in the execution status.

Cucumber Report

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Background in Cucumber

HOME

What is the Background in Cucumber?

The background is used in Cucumber to define a step or series of steps that are shared by all the tests in the feature file.  This helps to reduce redundancy and makes the feature file cleaner and easier to read.

A Background provides context for the scenarios that follow it. It may include one or more Given steps, which are executed before each scenario but after any Before hooks.

A Background is placed at the same level of indentation as the first Scenario/Example.

Below is an example of a Background in a Feature file.

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

  @MissingUsername
  Scenario: Login with blank username

    When User enters username as " " and password as "admin123"
    Then User should be able to see a message "Required" below Username

In the above example, we have two different scenarios, where a user is successfully able to log in to the application and an unsuccessful attempt to log in. But the common step is to open the website for both scenarios. This is why we created another Scenario for opening the browser but named it Background rather than a Scenario. So that it executes for both Scenarios.

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions {

    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {

        System.out.println("I am in Login Page");

    }

    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {

        System.out.println("Go to Home Page");

    }

    @Then("User should be able to login successfully and new page open")
    public void verifyLogin() {

        System.out.println("Home Page is opened");

    }

    @Then("User should be able to see a message {string} below Username")
    public void verifyMissingUsernameMessage(String message) {

        System.out.println("Login failed with an error message");
    }

}

We need a runner class to execute the feature file. Below is an example of the Runner class.

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(tags = "", features = "src/test/resources/features/LoginPage.feature", glue = "org.example.definitions",
        plugin = {})
public class CucumberRunnerTests extends AbstractTestNGCucumberTests {
}

The output of the above program is

Background with Hooks

Background can contain one or more Given steps, which are run before each scenario, but after any Before hooks.

Below is an example of the background with hooks. The feature file is the same. I’m just adding the hooks to the Step Definition class.

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions {

    @Before()
    public void beforeScenario(){
        System.out.println("Start the browser and Clear the cookies");
    }

    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {

        System.out.println("I am in Login Page");

    }

    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {

        System.out.println("Go to Home Page");

    }

    @Then("User should be able to login successfully and new page open")
    public void verifyLogin() {

        System.out.println("Home Page is opened");

    }

    @Then("User should be able to see a message {string} below Username")
    public void verifyMissingUsernameMessage(String message) {

        System.out.println("Login failed with an error message");
    }

  @After()
    public void afterScenario(){
        System.out.println("Log out the user and close the browser");
    }

}

The output of the above program is

Points to remember

  • The background should not be used to create complicated states unless the client requires that information.
    For example, if the client doesn’t care about the user and site names, use a higher-level step like Given I am logged in as a site owner
  • Keep the Background section brief.
    When reading the scenarios, the client must remember this information. Consider moving some of the irrelevant details into higher-level steps if the Background is longer than four lines.
  • Make your background section stand out
    Use interesting names and try to tell a story. The human brain remembers stories much better than it remembers names like “User A,” “User B,” “Site 1,” and so on.

How to create Jenkins pipeline for Cucumber tests

HOME

In the previous tutorial, I discussed the Jenkins pipeline. This tutorial will discuss the steps to create the Jenkins pipeline for Cucumber tests.

Prerequisite:

Jenkins was installed and started on the computer.

To generate Cucumber Report in Jenkins, we need to download HTML Publisher. Please refer to this tutorial to install the plugin – How to install Plugins in Jenkins

Implementation Steps

Step 1: Create a new pipeline project

  1. Give the Name of the project – Cucumber_PipelineDemo
  2. Click on the pipeline project. 
  3. Click on the OK button.

In the General section, enter the project description in the Description box.

Step 2: Scroll down to Pipeline

From the Definition field, choose the “Pipeline script from SCM” option. This option instructs Jenkins to obtain your Pipeline from Source Control Management (SCM), which will be your locally cloned Git repository.

From the SCM field, choose Git.

The Repositories section contains the Repository URL and Credentials.

In the Repository URL field, specify the directory path of the GitLab/GitHub project.

In the Credentials field, specify the username and password needed to log in to GitLab/GitHub.

In this case, I have the project is present in GitLab and using it.

Step 3: Create Jenkinsfile

Create and save a new text file with the name Jenkinsfile at the root of the project in the GitLab repository. Here, we are using the Cucumber project with Selenium and TestNG. To know more about the Integration of Cucumber with Serenity and TestNG, please refer to this tutorial – Implemention of ‘Masterthought’ Reports in Cucumber with TestNG.

For this tutorial, we are using Declarative syntax. The sample example is given below:

pipeline {
    agent any

    stages {
        stage('Test') {
            steps {

                // To run Maven on a Windows agent, use
                bat "mvn -D clean test"
            }

            post {
                
                // If Maven was able to run the tests, even if some of the test
                // failed, record the test results and archive the jar file.
                success {
                        cucumber buildStatus: 'null', 
                        customCssFiles: '', 
                        customJsFiles: '', 
                        failedFeaturesNumber: -1, 
                        failedScenariosNumber: -1, 
                        failedStepsNumber: -1, 
                        fileIncludePattern: '**/*.json', 
                        pendingStepsNumber: -1, 
                        skippedStepsNumber: -1, 
                        sortingMethod: 'ALPHABETICAL', 
                        undefinedStepsNumber: -1
                }
            }
        }
    }
}

Step 4: Specify branches to build a section under Repositories

  1. Branch Specifier – */master (This is my main branch)
  2. ScriptPath – Jenkinsfile

Click on the Apply and Save buttons.

We have created a new Maven project Cucumber_PipelineDemo” with the configuration to run the Cucumber Tests with TestNG.

Step 5: Execute the tests

Let’s execute it now by clicking on the “Build Now” button. 

Right-click on Build Number (here in my case it is #4) and click on Console Output to see the result.

Below is the test execution summary.

Step 6: Pipeline Steps

Once the execution is completed, and we want to see the Pipeline Steps, click on the Pipeline Steps mentioned on the left side of the page.

Step 7: View the Report

Once the execution is completed, go back to “Cucumber_PipelineDemo”. We can see below that the Cucumber report is generated.

We could see a link to view the “Cucumber Report“. Click on the Cucumber Report. It displays the  Report.

Tip: If you don’t see the Report UI intact, then you need to configure a simple groovy script. For that, go to Dashboard–>Manage Jenkins–>Script Console and add the script as:

	System.setProperty("hudson.model.DirectoryBrowserSupport.CSP","")

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Additional Tutorials

How to generate TestNG Report in Jenkins
Integration of Allure Report with Jenkins
How to generate HTML Reports in Jenkins
Integration of Cucumber Report with TestNG in Jenkins
How to create Jenkins pipeline for Selenium tests

Serenity with Jenkins

Last Updated On

HOME

In the previous tutorial, we have seen the Integration Of Jenkins With Selenium WebDriver. In this tutorial, we show you how to execute Serenity tests in Jenkins. 

Table of Contents

  1. Prerequisite
  2. Implementation Steps
    1. Create a new project using the Maven project plugin
    2. Build Management
    3. Select custom workspace
    4. Select “Publish HTML Reports” from “Post Build Actions”
    5. Execute the tests
    6. Serenity Report
  3. How to find the path of reports in Jenkins?

Prerequisite

Jenkins installed and started on the computer

To generate Serenity Report in Jenkins, we need to download HTML Publisher. Please refer to this tutorial to install the plugin – How to install Plugins in Jenkins

Implementation Steps

Step 1: Create a new project using the Maven project plugin

  1. Give the Name of the project.
  2. Click on the Maven project. 
  3. Click on the OK button.

In the General section, enter the project description in the Description box.

Step 2: Build Management

Go to the Build section of the new job.

  1. In the Root POM textbox, enter the full path to pom.xml
  2. In the Goals and options section, enter “clean test

Click on the Advanced button.

Step 3: Select custom workspace

Mention the full path of the project in the directory.

Step 4: Select “Publish HTML Reports” from “Post Build Actions”

Select “Publish HTML reports“. 

  1. HTML directory to archive – target/site/serenity
  2. Index page[s] – Index.html
  3. Report title – HTML Report

Click on the Apply and Save buttons.

We have created a new Maven project SerenityDemo” with the configuration to run the Serenity Tests and also to generate a Serenity Report after execution using Jenkins.

Step 5: Execute the tests

Let’s execute it now by clicking on the “Build Now” button. 

Right-click on Build Number (here in my case it is #5) and click on Console Output to see the result.

Below is the execution summary of the tests.

We can see below that the Serenity Reports are generated.

Once the execution is completed, click on “Back to Project“.

Step 6: Serenity Report

We could see a link to view ‘HTML Reports’. Click on the HTML Reports. It displays the Index.html Report of Serenity.

Serenity Report is in HTML format. So, we need to install HTML Publisher Plugin to view the Serenity Reports. Please refer to this tutorial to download and install the HTML Plugin in Jenkins – How to generate HTML Reports in Jenkins.

The Serenity Report looks like as shown below:

How to find the path of reports in Jenkins?

After running successfully, go to the job and click on the “Workspace”  link. As soon as we click on the above-mentioned link, we will be inside this directory. Now click on the “target” link.

As soon as we click on the above-mentioned link, we will be inside this directory. Now click on the “site/serenity”  link.

As soon as we click on the above-mentioned link, we will be inside this directory. Now we can see all the reports of Serenity.

This way, we could run Serenity tests and generate Serenity Reports using Jenkins.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Implemention of ‘Masterthought’ Reports in Cucumber with JUnit4

HOME

Masterthought library provides pretty HTML reports for Cucumber. The cucumber JSON file is used to generate the HTML for the website. This Java report publisher was made particularly with publishing cucumber reports to the Jenkins build server in mind. It releases aesthetically pleasing HTML reports with charts displaying the outcomes of cucumber runs.

Prerequisite

  1. Java 11 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed

This framework consists of:

  1. Selenium – 4.3.0
  2. Java 11
  3. Cucumber – 7.6.0
  4. Maven – 3.8.1
  5. JUnit– 4.13.2
  6. Cucumber Reporting Plugin – 5.7.4

Project Structure

Implementation Steps

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Setup Maven
  4. Install Cucumber Eclipse Plugin (For Eclipse IDE)
  5. Create a new Maven Project
  6. Add SeleniumJUnit4Cucumber, and Masterthought dependencies to the project
  7. Create a feature file under src/test/resources
  8. Create the test code locating the web elements in src/main/java
  9. Create the Step Definition class or Glue Code in src/test/java
  10. Create a JUnit4 Cucumber Runner class in src/test/java
  11. Run the tests from Command Line
  12. Cucumber Report Generation

Step 1- Download and Install Java

Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on the 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

To build a test framework, we need to add a number of dependencies to the project. It is a very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool that is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

Step 4 – Install Cucumber Eclipse Plugin (Only for Eclipse IDE)

The Cucumber Eclipse plugin is a plugin that allows eclipse to understand the Gherkin syntax. The Cucumber Eclipse Plugin highlights the keywords present in Feature File. Click here to know more – Install Cucumber Eclipse Plugin.

Step 5 – Create a new Maven Project

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

Group Id – com.example
Artifact Id – CucumberReportingJUnit4_Demo
Version – 0.0.1-SNAPSHOT
Package – com. example

Step 6 – Add SeleniumTestNGCucumber, and Masterthought dependencies to the project

Masterthought Dependency

<dependency>
            <groupId>net.masterthought</groupId>
            <artifactId>cucumber-reporting</artifactId>
            <version>${maven.cucumber.reporting.version}</version>
</dependency>

Masterthought Plugin

<plugin>
        <groupId>net.masterthought</groupId>
        <artifactId>maven-cucumber-reporting</artifactId>
        <version>${maven.cucumber.reporting.version}</version>
 
        <executions>
            <execution>
                <id>execution</id>
                <phase>test</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <projectName>Cucumber Reporting Example With JUnit4</projectName>
                    <outputDirectory>${project.build.directory}/cucumber-report-html</outputDirectory>
                    <inputDirectory>${project.build.directory}</inputDirectory>
                    <jsonFiles>
                        <param>**/*.json</param>
                    </jsonFiles>
                </configuration>
            </execution>
        </executions>
</plugin>

The complete POM.xml for the project 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.example</groupId>
	<artifactId>CucumberReportingJUnit4_Demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>


	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<cucumber.version>7.6.0</cucumber.version>
		<selenium.version>4.3.0</selenium.version>
		<webdrivermanager.version>5.2.1</webdrivermanager.version>
		<junit.version>4.13.2</junit.version>
		<apache.common.version>2.4</apache.common.version>
		<maven.compiler.plugin.version>3.10.1</maven.compiler.plugin.version>
		<maven.surefire.plugin.version>3.0.0-M7</maven.surefire.plugin.version>
		<maven.compiler.source.version>11</maven.compiler.source.version>
		<maven.compiler.target.version>11</maven.compiler.target.version>
		<maven.cucumber.reporting.version>5.7.4</maven.cucumber.reporting.version>
	</properties>

	<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>

		<!-- Web Driver Manager -->
		<dependency>
			<groupId>io.github.bonigarcia</groupId>
			<artifactId>webdrivermanager</artifactId>
			<version>${webdrivermanager.version}</version>
		</dependency>

		<!-- JUnit4 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<!-- Apache Common -->
		<dependency>
			<groupId>org.apache.directory.studio</groupId>
			<artifactId>org.apache.commons.io</artifactId>
			<version>${apache.common.version}</version>
		</dependency>

        <!-- MasterThought -->
		<dependency>
			<groupId>net.masterthought</groupId>
			<artifactId>cucumber-reporting</artifactId>
			<version>${maven.cucumber.reporting.version}</version>
		</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>
			</plugin>

			<plugin>
				<groupId>net.masterthought</groupId>
				<artifactId>maven-cucumber-reporting</artifactId>
				<version>${maven.cucumber.reporting.version}</version>

				<executions>
					<execution>
						<id>execution</id>
						<phase>test</phase>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<projectName>Cucumber Reporting Example With JUnit4</projectName>
							<outputDirectory>${project.build.directory}/</outputDirectory>
							<inputDirectory>${project.build.directory}</inputDirectory>
							<jsonFiles>
								<param>**/*.json</param>
							</jsonFiles>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Step 7 – Create a feature file (LoginPage.feature) containing all the test scenarios under src/test/resources/features

It is recommended to create a features folder in src/test/resources directory. Create all the feature files in this features folder. Feature file should be saved as an extension of .feature.

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                      |
   | $$$$$      | ££££££££  | Invalid credentials               |
   | admin      | Admin123  | Invalid credentials               | 
   | Admin123   | admin     | Invalid credentials               |
     

Step 8 – Create the test code locating the web elements in src/main/java

LoginPageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

	@FindBy(name = "username")
    public WebElement userName;
 
    @FindBy(name = "password")
    public WebElement password;
 
    @FindBy(id = "logInPanelHeading")
    public WebElement titleText;
 
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
    public WebElement login;
 
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
    public  WebElement errorMessage;
        
}

HomePageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

	@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6")
	public  WebElement homePageUserName;
 
}

LoginPageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;

public class LoginPageActions {

LoginPageLocators loginPageLocators = null; 
	
    public LoginPageActions() {

    	this.loginPageLocators = new LoginPageLocators();

		PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
	}
    
    public void login(String strUserName, String strPassword) {
    	 
        // Fill user name
    	loginPageLocators.userName.sendKeys(strUserName);
 
        // Fill password
    	loginPageLocators.password.sendKeys(strPassword);
 
        // Click Login button
    	loginPageLocators.login.click();
 
    }

    //Get the title of Login Page")
    public String getLoginTitle() {
        return loginPageLocators.titleText.getText();
    }
     
    // Get the error message of Login Page
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }

}

HomePageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;

public class HomePageActions {

	HomePageLocators homePageLocators = null;
   
	public HomePageActions() {
    	
		this.homePageLocators = new HomePageLocators();

		PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }
 
    // Get the User name from Home Page
    public String getHomePageText() {
        return homePageLocators.homePageUserName.getText();
    }

}

HelperClass

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class HelperClass {
	
	private static HelperClass helperClass;
	private static WebDriver driver;
    public final static int TIMEOUT = 10;
	
	 private HelperClass() {
		 
		WebDriverManager.chromedriver().setup();
	    driver = new ChromeDriver();
	    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
	    driver.manage().window().maximize();

	 }      	    	

    public static void openPage(String url) {
        driver.get(url);
    }
	
	public static WebDriver getDriver() {
		return driver;
				
	}
	
	public static void setUpDriver() {
		
		if (helperClass==null) {
			
			helperClass = new HelperClass();
		}
	}
	
	 public static void tearDown() {
		 
		 if(driver!=null) {
			 driver.close();
			 driver.quit();
		 }
		 
		 helperClass = null;

	 } 	
}

Step 9 – Create the Step Definition class or Glue Code in src/test/java

It is recommended to create a definitions folder in src/test/java directory. The StepDefinition files should be created in this definitions directory. within the folder called definitions.

LoginPageDefinitions

import org.junit.Assert;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions{	

	LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();
 
    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {
    	
    	HelperClass.openPage(url);
 
    }
 
    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {
 
        // login to application
        objLogin.login(userName, passWord);
 
        // go the next page
        
    }
    
    @Then("User should be able to login successfully and new page open")
    public void verifyLogin() {
 
        // Verify home page
       Assert.assertTrue(objHomePage.getHomePageText().contains("Dashboard"));
 
    }
    
    @Then("User should be able to see error message {string}")
    public void verifyErrorMessage(String expectedErrorMessage) {
 
        // Verify error message
    	Assert.assertEquals(expectedErrorMessage,objLogin.getErrorMessage());
 
    }
    
}

Hooks

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class Hooks {
	
	@Before
    public static void setUp() {

       HelperClass.setUpDriver();
    }
	
	@After
	public static void tearDown(Scenario scenario) {
		//validate if scenario has failed
		if(scenario.isFailed()) {
			final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
			scenario.attach(screenshot, "image/png", scenario.getName()); 
		}	
	
		HelperClass.tearDown();
	}
}


Step 10 – Create a JUnit 4 Cucumber Runner class in src/test/java

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/LoginPage.feature", glue = "com.example.definitions",
  plugin= {"pretty", "json:target/cucumber-reports/reports.json",
"json:target/cucumber-reports/cucumber.runtime.formatter.JSONFormatter"})
 
public class CucumberRunnerTests  {
 
}

Step 11 – Run the tests from Command Line

Use the below command to execute the tests

mvn clean test

The output of the above program is

Step 12 – Cucumber Report Generation

Refresh your project and check inside \target\cucumber-html-reports that the report generated with name feature-overview.

There are different types of HTML reports gets generated as a part of the test execution cycle.

1. feature-overview – This HTML report gives an overall overview of test execution. Main HTML report which covers all different sections like Features, Tags, Steps, and Failures.

2. failures-overview – This HTML report gives an overview of all failed tests.

3. step-overview – This HTML report shows step statistics for the current cycle.

4. tag-overview – This HTML report shows passing and failing statistics for different tags used in test execution.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Implemention of ‘Masterthought’ Reports in Cucumber with TestNG

Last Updated On

HOME

Masterthought library provides pretty HTML reports for Cucumber. The cucumber JSON file is used to generate the HTML for the website. This Java report publisher was made particularly with publishing cucumber reports to the Jenkins build server in mind. It releases aesthetically pleasing HTML reports with charts displaying the outcomes of cucumber runs.

Cucumber lacks a sophisticated reporting feature. Cucumber generates a number of simple reports as part of the BDD framework; using the output from these same reports, we can use the Masterthought reporting plugin to produce more extensive HTML reports. Masterthought reporting plugin generates not only fancy reports but also detailed ones by reading a default report ‘cucumber.json’  generated by cucumber.

Table of Contents

  1. Prerequisite
  2. Dependency List
  3. Project Structure
  4. Implementation Steps
    1. Download and Install Java
    2. Download and setup Eclipse IDE on the system
    3. Setup Maven
    4. Install Cucumber Eclipse Plugin (Only for Eclipse IDE
    5. Create a new Maven Project
    6. Add Selenium, TestNG, Cucumber, and Masterthought dependencies to the project
    7. Create a feature file (LoginPage.feature) containing all the test scenarios under src/test/resources/features
    8. Create the test code locating the web elements in src/main/java
    9. Create the Step Definition class or Glue Code in src/test/java
    10. Create a TestNG Cucumber Runner class in src/test/java
    11. Create testng.xml
    12. Run the tests from Command Line
    13. Cucumber Report Generation

Prerequisite

  1. Java 11 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed

Dependency List

  1. Selenium – 4.3.0
  2. Java 11
  3. Cucumber – 7.6.0
  4. Maven – 3.8.1
  5. TestNG – 7.6.0
  6. Cucumber Reporting Plugin – 5.7.4

Project Structure

Implementation Steps

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Setup Maven
  4. Install Cucumber Eclipse Plugin (For Eclipse IDE)
  5. Create a new Maven Project
  6. Add SeleniumTestNG, Cucumber, and Masterthought dependencies to the project
  7. Create a feature file under src/test/resources
  8. Create the test code locating the web elements in src/main/java
  9. Create the Step Definition class or Glue Code in src/test/java
  10. Create a TestNG Cucumber Runner class in src/test/java
  11. Create testng.xml
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Step 1- Download and Install Java

Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on the 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

To build a test framework, we need to add a number of dependencies to the project. It is a very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool that is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

Step 4 – Install Cucumber Eclipse Plugin (Only for Eclipse IDE)

The Cucumber Eclipse plugin is a plugin that allows eclipse to understand the Gherkin syntax. The Cucumber Eclipse Plugin highlights the keywords present in Feature File. Click here to know more – Install Cucumber Eclipse Plugin.

Step 5 – Create a new Maven Project

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

Group Id – com.example
Artifact Id – CucumberReportingTestNG_Demo
Version – 0.0.1-SNAPSHOT
Package – com. example.testng

Step 6 – Add Selenium, TestNG, Cucumber, and Masterthought dependencies to the project

Masterthought Dependency

<dependency>
			<groupId>net.masterthought</groupId>
			<artifactId>cucumber-reporting</artifactId>
			<version>${maven.cucumber.reporting.version}</version>
</dependency>

Masterthought Plugin

<plugin>
		<groupId>net.masterthought</groupId>
		<artifactId>maven-cucumber-reporting</artifactId>
		<version>${maven.cucumber.reporting.version}</version>

		<executions>
			<execution>
				<id>execution</id>
				<phase>test</phase>
				<goals>
					<goal>generate</goal>
				</goals>
				<configuration>
					<projectName>Cucumber Reporting Example</projectName>
					<outputDirectory>${project.build.directory}/cucumber-report-html</outputDirectory>
					<inputDirectory>${project.build.directory}</inputDirectory>
					<jsonFiles>
						<param>**/*.json</param>
					</jsonFiles>
				</configuration>
			</execution>
		</executions>
</plugin>

The complete POM.xml for the project 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.example</groupId>
	<artifactId>CucumberReportingTestNG_Demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<cucumber.version>7.6.0</cucumber.version>
		<selenium.version>4.3.0</selenium.version>
		<webdrivermanager.version>5.2.1</webdrivermanager.version>
		<testng.version>7.6.0</testng.version>
		<apache.common.version>2.4</apache.common.version>
		<maven.compiler.plugin.version>3.10.1</maven.compiler.plugin.version>
		<maven.surefire.plugin.version>3.0.0-M7</maven.surefire.plugin.version>
		<maven.compiler.source.version>11</maven.compiler.source.version>
		<maven.compiler.target.version>11</maven.compiler.target.version>
		<maven.cucumber.reporting.version>5.7.4</maven.cucumber.reporting.version>
	</properties>

	<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>

		<!-- Web Driver Manager -->
		<dependency>
			<groupId>io.github.bonigarcia</groupId>
			<artifactId>webdrivermanager</artifactId>
			<version>${webdrivermanager.version}</version>
		</dependency>

		<!-- TestNG -->
		<dependency>
			<groupId>org.testng</groupId>
			<artifactId>testng</artifactId>
			<version>${testng.version}</version>
			<scope>test</scope>
		</dependency>

		<!-- Apache Common -->
		<dependency>
			<groupId>org.apache.directory.studio</groupId>
			<artifactId>org.apache.commons.io</artifactId>
			<version>${apache.common.version}</version>
		</dependency>

       <!-- Cucumber Reporting-->
		<dependency>
			<groupId>net.masterthought</groupId>
			<artifactId>cucumber-reporting</artifactId>
			<version>${maven.cucumber.reporting.version}</version>
		</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>
					<testFailureIgnore>True</testFailureIgnore>
					<suiteXmlFiles>
						<suiteXmlFile>testng.xml</suiteXmlFile>
					</suiteXmlFiles>
				</configuration>
			</plugin>

			<plugin>
				<groupId>net.masterthought</groupId>
				<artifactId>maven-cucumber-reporting</artifactId>
				<version>${maven.cucumber.reporting.version}</version>

				<executions>
					<execution>
						<id>execution</id>
						<phase>test</phase>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<projectName>Cucumber Reporting Example</projectName>
							<outputDirectory>${project.build.directory}/cucumber-report-html</outputDirectory>
							<inputDirectory>${project.build.directory}</inputDirectory>
							<jsonFiles>
								<param>**/*.json</param>
							</jsonFiles>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Step 7 – Create a feature file (LoginPage.feature) containing all the test scenarios under src/test/resources/features

It is recommended to create a features folder in src/test/resources directory. Create all the feature files in this features folder. Feature file should be saved as an extension of .feature.

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                       |
   | $$$$$        | ££££££££  | Invalid credentials               |
   | admin        | Admin123  | Invalid credentials              | 

Step 8 – Create the test code locating the web elements in src/main/java

LoginPageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

	@FindBy(name = "username")
    public WebElement userName;
 
    @FindBy(name = "password")
    public WebElement password;
 
    @FindBy(id = "logInPanelHeading")
    public WebElement titleText;
 
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
    public WebElement login;
 
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
    public  WebElement errorMessage;
        
    @FindBy(xpath = "//*[@href='https://www.facebook.com/OrangeHRM/mycompany']") //Invalid Xpath
    public  WebElement faceBookIcon;  
    
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
    public WebElement missingUsernameErrorMessage;
}

HomePageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

	@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6")
	public  WebElement homePageUserName;
 
}

LoginPageActions

import org.openqa.selenium.support.PageFactory;
import com.example.testng.locators.LoginPageLocators;
import com.example.testng.utils.HelperClass;

public class LoginPageActions {

LoginPageLocators loginPageLocators = null; 
	
    public LoginPageActions() {

    	this.loginPageLocators = new LoginPageLocators();

		PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
	}
    
    public void login(String strUserName, String strPassword) {
    	 
        // Fill user name
    	loginPageLocators.userName.sendKeys(strUserName);
 
        // Fill password
    	loginPageLocators.password.sendKeys(strPassword);
 
        // Click Login button
    	loginPageLocators.login.click();
 
    }
 
    //Get the title of Login Page")
    public String getLoginTitle() {
        return loginPageLocators.titleText.getText();
    }
      
    // Get the error message of Login Page
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }
      
}

HomePageActions

import org.openqa.selenium.support.PageFactory;
import com.example.testng.locators.HomePageLocators;
import com.example.testng.utils.HelperClass;

public class HomePageActions {

	HomePageLocators homePageLocators = null;
   
	public HomePageActions() {
    	
		this.homePageLocators = new HomePageLocators();

		PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }
 
    // Get the User name from Home Page
    public String getHomePageText() {
        return homePageLocators.homePageUserName.getText();
    }

}

HelperClass

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class HelperClass {
	
	private static HelperClass helperClass;
	
	private static WebDriver driver;
    public final static int TIMEOUT = 10;
	
	 private HelperClass() {
		 
			WebDriverManager.chromedriver().setup();
	    	driver = new ChromeDriver();
	    	driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
	        driver.manage().window().maximize();

	 }      
	    	
    public static void openPage(String url) {
        driver.get(url);
    }
	
	public static WebDriver getDriver() {
		return driver;
				
	}
	
	public static void setUpDriver() {
		
		if (helperClass==null) {
			
			helperClass = new HelperClass();
		}
	}

	 public static void tearDown() {
		 
		 if(driver!=null) {
			 driver.close();
			 driver.quit();
		 }
		 
		 helperClass = null;

	 } 
	
}

Step 9 – Create the Step Definition class or Glue Code in src/test/java

It is recommended to create a definitions folder in src/test/java directory. The StepDefinition files should be created in this definitions directory. within the folder called definitions.

LoginPageDefinitions

import org.junit.Assert;
import com.example.junit.actions.ForgetPasswordPageActions;
import com.example.junit.actions.HomePageActions;
import com.example.junit.actions.LoginPageActions;
import com.example.junit.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions{
	
	LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();
    ForgetPasswordPageActions objForgotPasswordPage = new ForgetPasswordPageActions();
		
 
    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {
    	
    	HelperClass.openPage(url);
 
    }
 
    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {
 
        // login to application
        objLogin.login(userName, passWord);
 
        // go the next page
        
    }
    
    @Then("User should be able to login successfully and new page open")
    public void verifyLogin() {
 
        // Verify home page
        Assert.assertTrue(objHomePage.getHomePageText().contains("Dashboard"));
 
    }
    
    @Then("User should be able to see error message {string}")
    public void verifyErrorMessage(String expectedErrorMessage) {
 
        // Verify home page
        Assert.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);
 
    }
     
}

Hooks

import com.example.junit.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;

public class Hooks {
	
	@Before
    public static void setUp() {

       HelperClass.setUpDriver();
    }
	
	@After
	public static void tearDown() {
	
		HelperClass.tearDown();
	}
}

Step 10 – Create a TestNG Cucumber Runner class in src/test/java

We need to create a class called Runner class to run the tests. This class will use the TestNG annotation @RunWith(), which tells TestNG what is the test runner class. TestRunner should be created under src/test/java within the folder called runner.

AbstractTestNGCucumberTests – Runs each cucumber scenario found in the features as a separate test.

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
 
@CucumberOptions(tags = "", features = "src/test/resources/features/LoginPage.feature", glue = "com.example.testng.definitions",
    plugin= {"pretty", "html:test-output","json:target/cucumber/cucumber.json", "html:target/cucumber-html-report"})
 
public class CucumberRunnerTests extends AbstractTestNGCucumberTests {
 
}

Step 11 – Create testng.xml

TestNG.xml is used to run multiple tests in a single execution.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <test name="Cucumber Reporting">
  
  <classes>
  <class name = "com.example.testng.runner.CucumberRunnerTests"/>
  </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

Step 12 – Run the tests from Command Line

Use the below command to execute the tests.

mvn clean test

The output of the above program is

Step 13 – Cucumber Report Generation

Refresh your project and check inside \target\cucumber-html-reports that the report generated with name feature-overview.

There are different types of HTML reports gets generated as a part of the test execution cycle.

1. feature-overview – This HTML report gives an overall overview of test execution. Main HTML report which covers all different sections like Features, Tags, Steps, and Failures.

2. failures-overview – This HTML report gives an overview of all failed tests.

3. step-overview – This HTML report shows step statistics for the current cycle.

4. tag-overview – This HTML report shows passing and failing statistics for different tags used in test execution.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Gradle Project with Cucumber, Selenium and JUnit4

HOME

The previous tutorial explained the Integration of Cucumber with Selenium and JUnit4 in a Maven Project. This tutorial explains the test automation framework based on Gradle, Cucumber, Selenium, and JUnit4.

Pre Requisite:

  1. Java 8 or above installed
  2. Eclipse or IntelliJ IDE installed
  3. Gradle Installed
  4. Environment variables JAVA_HOME and GRADLE_HOME are correctly configured

In this tutorial, I’ll create a BDD Framework for the testing of web applications using Cucumber, and Selenium WebDriver with JUnit4. This framework consists of:-

  1. Cucumber Java- 7.6.0
  2. Cucumber JUnit– 7.6.0
  3. Java 11
  4. JUnit4 – 4.13.2
  5. Gradle – 7.5.1
  6. Selenium – 4.3.0

Project Structure

Steps to set up Cucumber Test Automation Framework with Selenium and TestNG

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Install and setup Gradle
  4. Install Cucumber Eclipse Plugin (For Eclipse IDE)
  5. Create a new Gradle Project
  6. Add SeleniumJUnit4, and Cucumber dependencies to the build.gradle
  7. Create a feature file under src/test/resources
  8. Create the classes for locators, actions, and utilities in src/main/java
  9. Create the Step Definition class or Glue Code in src/test/java
  10. Create a Hook class to contain the initialization and closing of the browser in src/test/java
  11. Create a JUnit4 Cucumber Runner class in src/test/java
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Implementation Steps

Step 1- Download and Install Java

Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on the system

The Eclipse IDE (integrated development environment) provides strong support for Java developers. Click here to know How to install Eclipse.

Step 3 – Setup Maven

To build a test framework, we need to add a number of dependencies to the project. Click here to know How to install Maven.

Step 4 – Install Cucumber Eclipse Plugin

The cucumber plugin is an Eclipse plugin that allows eclipse to understand the Gherkin syntax. When we are working with cucumber we will write the feature files that contain Feature, Scenario, Given, When, Then, And, But, Tags, Scenario Outline, and Examples. By default, eclipse doesn’t understand these keywords so it doesn’t show any syntax highlighter. Cucumber Eclipse Plugin highlights the keywords present in Feature File. Refer to this tutorial to get more detail – How to setup Cucumber with Eclipse.

Step 5 – Create a new Gradle Project

Below are the steps to create the Gradle project from the command line.

If you want to create the Gradle project from Eclipse IDE, click here to know How to create a Gradle Java project. Below is the structure of the Gradle project.

Step 6 – Add Selenium, JUnit4, and Cucumber dependencies to the build.gradle

Add below mentioned Selenium, JUnit4, and Cucumber dependencies to the project.

/*
 * This file was generated by the Gradle 'init' task.
 *
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

java {
    sourceCompatibility = 11
    targetCompatibility = 11
}

dependencies {

    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-junit:7.6.0'  
    
    // Use JUnit test framework.
    testImplementation 'junit:junit:4.13.2'

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:30.1.1-jre'
    implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
    implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'
}

application {
    // Define the main class for the application.
    mainClass = 'com.example.App'
}

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

task cucumber() {
    dependsOn assemble, testClasses
    doLast {
        
        javaexec {      
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
               
            args = ['--plugin', 'pretty', 
            '--glue', 'com.example.definitions', 'src/test/resources'
            ]
        }

    }
}

I have added WebDriverManager dependency to the POM.xml to download the driver binaries automatically. To know more about this, please refer to this tutorial – How to manage driver executables using WebDriverManager.

Step 7 – Create a feature file in the src/test/resources directory

Create a folder with name features. Now, create the feature file in this folder. The feature file should be saved with the extension .feature. This feature file contains the test scenarios created to test the application. The Test Scenarios are written in Gherkins language in the format of Given, When, Then, And, But.

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 sucessfully 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               |
  | $$$$$$     | %%%%%     | Invalid credentials               |
  
   @MissingUsername @FailedTest
   Scenario: Verify error message when username is missing
     
    When User enters username as "" and password as "admin123"
    Then User should be able to see error message for empty username as "Empty Username"
      

Step 8 – Create the classes for locators, actions, and utilities in src/main/java

Below is the sample code of the LoginPageLocators.

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

	@FindBy(name = "username")
    public WebElement userName;
  
    @FindBy(name = "password")
    public WebElement password;
  
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
    public WebElement login;
  
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
    public  WebElement errorMessage;
     
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
    public WebElement missingUsernameErrorMessage;
     
}

Below is the sample code for the HomePageLocators.

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

	   @FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
	   public  WebElement homePageUserName;
 
}

Create the action classes for each web page. These action classes contain all the methods needed by the step definitions. In this case, I have created 2 action classes – LoginPageActions and HomePageActions.

LoginPageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;

public class LoginPageActions {

	LoginPageLocators loginPageLocators = null; 
	
    public LoginPageActions() {

    	this.loginPageLocators = new LoginPageLocators();
		PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
	}
    
    public void login(String strUserName, String strPassword) {
 
        // Fill user name
    	loginPageLocators.userName.sendKeys(strUserName);
 
        // Fill password
    	loginPageLocators.password.sendKeys(strPassword);
 
        // Click Login button
    	loginPageLocators.login.click();
 
    }
    
    // Get the error message when invalid credentials are provided
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }
    
   // Get the error message when username is blank
   public String getMissingUsernameText() {
        return loginPageLocators.missingUsernameErrorMessage.getText();
    }    
}

HomePageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;

public class HomePageActions {

	HomePageLocators homePageLocators = null;
   
	public HomePageActions() {
    	
		this.homePageLocators = new HomePageLocators();

		PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }

 
    // Get the User name from Home Page
    public String getHomePageText() {
        return homePageLocators.homePageUserName.getText();
    }

}

Create a Helper class where we are initializing the web driver, initializing the web driver wait, defining the timeouts, and creating a private constructor of the class, it will declare the web driver, so whenever we create an object of this class, a new web browser is invoked. 

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class HelperClass {
	
	private static HelperClass helperClass;	
	private static WebDriver driver;
    public final static int TIMEOUT = 10;
		
	 private HelperClass() {
		 
			WebDriverManager.chromedriver().setup();
	    	driver = new ChromeDriver();
	        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
	        driver.manage().window().maximize();

	 }      
	    	
    public static void openPage(String url) {
        driver.get(url);
    }
	
	public static WebDriver getDriver() {
		return driver;	
	}
	
	public static void setUpDriver() {
		
		if (helperClass==null) {
			
			helperClass = new HelperClass();
		}
	}

	 public static void tearDown() {
		 
		 if(driver!=null) {
			 driver.close();
			 driver.quit();
		 }
		 
		 helperClass = null;

	 } 	
}

Step 9 – Create the Step Definition class or Glue Code in src/test/java

Now, we need to create the Step Definition of the Feature File

LoginPageDefinitions.java

import org.junit.Assert;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions {
		
	LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();
		
    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {
    	
    	HelperClass.openPage(url);
    }
 
    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {
 
        objLogin.login(userName, passWord);     
    }
 
    @Then("User should be able to login sucessfully and new page open")
    public void verifyLogin() {
 
        Assert.assertTrue(objHomePage.getHomePageText().contains("Employee Information"));
    }
    
    @Then("User should be able to see error message {string}")
    public void verifyErrorMessageForInvalidCredentials(String expectedErrorMessage) {
 
        Assert.assertEquals(expectedErrorMessage,objLogin.getErrorMessage());
    }
     
    @Then("User should be able to see error message for empty username as {string}")
    public void verifyErrorMessageForEmptyUsername(String expectedErrorMessage) {
    	 
        Assert.assertEquals(expectedErrorMessage,objLogin.getMissingUsernameText());
 
    }   
}

Step 10 – Create a Hook class to contain the initialization and closing of the browser in src/test/java

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class BaseClass {

	@Before
    public static void setUp() {

       HelperClass.setUpDriver();
    }

	@After
	public static void tearDown(Scenario scenario) {


		//validate if scenario has failed
		if(scenario.isFailed()) {
			final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
			scenario.attach(screenshot, "image/png", scenario.getName()); 
		}	
	
		HelperClass.tearDown();
	}
}

Step 11 – Create a JUnit Cucumber Runner class in src/test/java

Cucumber needs a TestRunner class to run the feature files. It is suggested to create a folder with the name of the runner in the src/test/java directory and create the Cucumber TestRunner class in this folder. Below is the code of the Cucumber TestRunner class.

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/LoginPage.feature"}, glue = {"com.example.definitions"})
   
public class CucumberRunnerTests {
   
}

Step 12 – Run the tests from Command Line

Run the below command in the command prompt to run the tests and to get the test execution report.

gradle cucumber

The output of the above program is

Step 13 – Cucumber Report Generation

To get Cucumber Test Reports, add cucumber.properties under src/test/resources and add the below instruction in the file

cucumber.publish.enabled=true

Below is the image of the Cucumber Report generated using the Cucumber Service.

In the above example, as we can see, one of the tests has failed. So, when a test fails, we have written the code to take a screenshot of the failed step. The highlighted box above shows the image of the failed test. You can click on that to see the screenshot.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Gradle – Extent Report Version 5 for Cucumber, Selenium, and TestNG

HOME

The previous tutorial explained the generation of Extent Reports Version 5 for Cucumber 7 and TestNG in a Maven project. In this tutorial, I will explain the steps to create an Extent Report Version 5 for Cucumber, Selenium, and TestNG in a Gradle project.

Prerequisite

  1. Java 8 or above installed
  2. Eclipse or IntelliJ IDE installed
  3. Gradle Installed
  4. Environment variables JAVA_HOME and GRADLE_HOME are correctly configured

In this tutorial, I’ll create a BDD Framework for the testing of web applications using Cucumber, and Selenium WebDriver with TestNG.

  1. Cucumber Java- 7.6.0
  2. Cucumber JUnit– 7.6.0
  3. Java 11
  4. TestNG – 7.6.0
  5. Gradle – 7.5.1
  6. Selenium – 4.3.0
  7. ExtentReport – 5.0.9
  8. GrassHopper Cucumber Adapter – 1.7.0

Implementation Steps

There is a tutorial that explains the Integration of Cucumber, Selenium, and TestNG in a Gradle project. Please refer to this tutorial – Gradle Project with Cucumber, Selenium and TestNG.

Step 1 – Add Extent Report dependency to the build.gradle

To create an Extent Report, we need to add the below-mentioned dependency in the build.gradle

implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
implementation 'com.aventstack:extentreports:5.0.9'  

Step 2 – Add ExtentCucumberAdapter plugin to task cucumber

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty', 
            '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm',
            '--plugin', 'com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:',
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 3 – Add Cucumber, Selenium, and TestNG dependencies in build.gradle

dependencies {

    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-junit:7.6.0'
    
     //TestNG  
     testImplementation 'org.testng:testng:7.6.0'
    
    //ExtentReport    
    implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
    implementation 'com.aventstack:extentreports:5.0.9' 

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:30.1.1-jre'
    implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
    implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'
}

The complete build.gradle is shown below:

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

java {
    sourceCompatibility = 11
    targetCompatibility = 11
}

dependencies {
   
    // Use TestNG framework, also requires calling test.useTestNG() below
    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-testng:7.6.0'
             
    //TestNG  
     testImplementation 'org.testng:testng:7.6.0'
      
    //ExtentReport    
     implementation 'tech.grasshopper:extentreports-cucumber7-adapter:1.7.0'
     implementation 'com.aventstack:extentreports:5.0.9'  
      
     //Others  
     implementation 'com.google.guava:guava:31.0.1-jre'
     implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
     implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'

}

application {
    // Define the main class for the application.
    mainClass = 'com.example.App'
}

tasks.named('test') {
    // Use TestNG for unit tests.
    useTestNG()
}

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty', 
            '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm',
            '--plugin', 'com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:',
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 4 – Create Locator and Action classes and Step Definition corresponding to the feature file

As mentioned above, there is another tutorial that explains the project structure as well as the feature file and corresponding Step Definitions, please refer to this tutorial – Gradle Project with Cucumber, Selenium, and TestNG.

Step 5 – Create extent.properties file in the resources folder and paste the below code

#Extent Report
extent.reporter.spark.start=true
extent.reporter.spark.out=Reports/Spark.html
 
#PDF Report
extent.reporter.pdf.start=true
extent.reporter.pdf.out=PdfReport/ExtentPdf.pdf
 
#HTML Report
extent.reporter.html.start=true
extent.reporter.html.out=HtmlReport/ExtentHtml.html
 
#FolderName
basefolder.name=ExtentReports/SparkReport_
basefolder.datetimepattern=d_MMM_YY HH_mm_ss
 
#Screenshot
screenshot.dir=/Screenshots/
screenshot.rel.path=../Screenshots/
 
#Base64
extent.reporter.spark.base64imagesrc=true
 
#System Info
systeminfo.os=windows
systeminfo.version=10

Step 6 – Execute the Tests

Go to the app project and run the tests, using the below command

gradle cucumber

The output of the above program is

Step 7 – View the ExtentReports

Refresh the project and will see a new folder – SparkReport_ which further contains 4 folders -Html Report, Pdf Report, Reports, and Screenshots.

The Extent Report will be present in the Report’s folder with the name Spark.html. PDF Report is present in the Pdf Report folder and HTML Report is present in the HTML report folder. We can see that the Screenshot’s folder is empty because we have used the base64imagesrc feature, which resulted in no physical screenshots. The screenshots are embedded in the reports.

Right-click and open the ExtentHtml.html report with the Web Browser. The report also has a summary section that displays the summary of the execution. The summary includes the overview of the pass/fail using a pictogram, start time, end time, and pass/fail details of features as shown in the image below.

ExtentHtml.html

The failed test has a screenshot embedded in it. Double-click on mase64image, and it will open the screenshot in full screen.

Screenshot of failed Test Case

PDF Report

To know more about PDF Report generation, please refer to this tutorial – PDF ExtentReport for Cucumber and TestNG.

Spark Report

Right-click and open the Spark.html report with the Web Browser.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Gradle – Allure Report for Cucumber, Selenium and TestNG

HOME

The previous tutorial explained generation of Allure Report with Cucumber5, Selenium and TestNG in a Maven project. In this tutorial, I will explain the steps to create an Allure Report with Cucumber, Selenium and TestNG in a Gradle project.

Pre Requisite:

  1. Java 8 or above installed
  2. Eclipse or IntelliJ IDE installed
  3. Gradle Installed
  4. Environment variables JAVA_HOME and GRADLE_HOME correctly configured

In this tutorial, I’ll create a BDD Framework for the testing of web applications using CucumberSelenium WebDriver with TestNG. This framework consists of:-

  1. Cucumber Java- 7.6.0
  2. Cucumber TestNG – 7.6.0
  3. Java 11
  4. TestNG – 7.6.0
  5. Gradle – 7.5.1
  6. Selenium – 4.3.0
  7. AspectJ Weaver – 1.9.7

Project Structure

Implementation Steps

  1. Add Cucumber, Selenium, TestNG, and Allure-TestNG dependencies in build.gradle
  2. Create Locator and Action classes and Step Definition corresponding to the feature file and Test Runner Class
  3. Execute the Tests
  4. Generate Allure Report

There is a tutorial that explains the Integration of Cucumber, Selenium and TestNG in a Gradle project. Please refer to this tutorial – Gradle Project with Cucumber, Selenium and TestNG.

Step 1 – Add Cucumber, Selenium, TestNG, and Allure-TestNG dependencies in build.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
    id 'io.qameta.allure' version '2.11.0'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

java {
    sourceCompatibility = 11
    targetCompatibility = 11
}

dependencies {
   
    // Use TestNG framework, also requires calling test.useTestNG() below
    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-testng:7.6.0'
          
     // Allure 
     implementation 'io.qameta.allure:allure-cucumber7-jvm:2.19.0'
     runtimeOnly 'org.aspectj:aspectjweaver:1.9.7'
     
     //TestNG  
      testImplementation 'org.testng:testng:7.6.0'
      
     //Others  
     implementation 'com.google.guava:guava:31.0.1-jre'
     implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
     implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'

}

application {
    // Define the main class for the application.
    mainClass = 'com.example.App'
}

tasks.named('test') {
    // Use TestNG for unit tests.
    useTestNG()
}

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {
         systemProperty("allure.results.directory", "build/allure-results")
         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty',
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 2 – Create Locator and Action classes and Step Definition corresponding to the feature file and Test Runner Class

As mentioned above, there is another tutorial that explains the project structure as well as the feature file and corresponding Step Definitions, please refer to this tutorial – Gradle Project with Cucumber, Selenium and TestNG.

Step 3 – Execute the Tests

Go to the app project and run the tests, using the below command

gradle cucumber

The output of the test execution is

Step 4 – Generate the Allure Report

Once the test execution is finished, a folder named allure-results will be generated in the build folder.

Note:- Make sure that you move to folder app, because build folder is present in app folder.

To generate Allure Report, use the below command

allure serve build/allure-results

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

Allure Report Dashboard

The overview page hosts several default widgets representing basic characteristics of your project and test environment.

  1. Statistics – overall report statistics.
  2. Launches – if this report represents several test launches, statistics per launch will be shown here.
  3. Behaviors – information on results aggregated according to stories and features.
  4. Executors – information on test executors that were used to run the tests.
  5. History Trend – if tests accumulated some historical data, its trend will be calculated and shown on the graph.
  6. Environment – information on the test environment.

Categories in Allure Report

The 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: 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.

Behaviors of Allure Report

This tab groups test results according to Epic, Feature, Story, Test Severity, Test Description, Test Steps, and so on.

Packages in Allure Report

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

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

Gradle Project with Cucumber, Selenium and TestNG

HOME

The previous tutorial explained the Integration of Cucumber with Selenium and TestNG in a Maven Project. This tutorial explains the test automation framework based on Gradle, Cucumber, Selenium, and TestNG.

Pre Requisite:

  1. Java 8 or above installed
  2. Eclipse or IntelliJ IDE installed
  3. Gradle Installed
  4. Environment variables JAVA_HOME and GRADLE_HOME are correctly configured

In this tutorial, I’ll create a BDD Framework for the testing of web applications using Cucumber, and Selenium WebDriver with TestNG. This framework consists of:-

  1. Cucumber Java- 7.6.0
  2. Cucumber TestNG – 7.6.0
  3. Java 11
  4. TestNG – 7.6.0
  5. Gradle – 7.5.1
  6. Selenium – 4.3.0

Project Structure

Steps to set up Cucumber Test Automation Framework with Selenium and TestNG

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Install and setup Gradle
  4. Install Cucumber Eclipse Plugin (For Eclipse IDE)
  5. Create a new Gradle Project
  6. Add SeleniumTestNG, and Cucumber dependencies to the build.gradle
  7. Create a feature file under src/test/resources
  8. Create the classes for locators, actions and utilities in src/main/java
  9. Create the Step Definition class or Glue Code in src/test/java
  10. Create a Hook class to contain the initialization and closing of browser in src/test/java
  11. Create a TestNG Cucumber Runner class in src/test/java
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Implementation Steps

Step 1- Download and Install Java

Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on the system

The Eclipse IDE (integrated development environment) provides strong support for Java developers. Click here to know How to install Eclipse.

Step 3 – Setup Maven

To build a test framework, we need to add a number of dependencies to the project. Click here to know How to install Maven.

Step 4 – Install Cucumber Eclipse Plugin

The cucumber plugin is an Eclipse plugin that allows eclipse to understand the Gherkin syntax. When we are working with cucumber we will write the feature files that contain Feature, Scenario, Given, When, Then, And, But, Tags, Scenario Outline, and Examples. By default, eclipse doesn’t understand these keywords so it doesn’t show any syntax highlighter. Cucumber Eclipse Plugin highlights the keywords present in Feature File. Refer to this tutorial to get more detail – How to setup Cucumber with Eclipse.

Step 5 – Create a new Gradle Project

Below are the steps to create the Gradle project from the command line.

If you want to create the Gradle project from Eclipse IDE, click here to know How to create a Gradle Java project. Below is the structure of the Gradle project.

Step 6 – Add Selenium, TestNG, and Cucumber dependencies to the build.gradle

Add below mentioned Selenium, TestNG, and Cucumber dependencies to the project.

I have added WebDriverManager dependency to the POM.xml to download the driver binaries automatically. To know more about this, please refer to this tutorial – How to manage driver executables using WebDriverManager.

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java application project to get you started.
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
    id 'io.qameta.allure' version '2.11.0'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

java {
    sourceCompatibility = 11
    targetCompatibility = 11
}

dependencies {
   
    // Use TestNG framework, also requires calling test.useTestNG() below
    testImplementation 'io.cucumber:cucumber-java:7.6.0'
    testImplementation 'io.cucumber:cucumber-testng:7.6.0'
            
     //TestNG  
      testImplementation 'org.testng:testng:7.6.0'
      
     //Others  
     implementation 'com.google.guava:guava:31.0.1-jre'
     implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
     implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'
}

application {
    // Define the main class for the application.
    mainClass = 'com.example.App'
}

tasks.named('test') {
    // Use TestNG for unit tests.
    useTestNG()
}

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

task cucumber() {
    dependsOn assemble, testClasses
    doLast {
        javaexec {
         
            main = "io.cucumber.core.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['--plugin', 'pretty', 
            '--glue', 'com.example.definitions', 'src/test/resources']
        }
    }
}

Step 7 – Create a feature file in the src/test/resources directory

Create a folder with name features. Now, create the feature file in this folder. The feature file should be saved with the extension .feature. This feature file contains the test scenarios created to test the application. The Test Scenarios are written in Gherkins language in the format of Given, When, Then, And, But.

Below is an example of the Feature File.

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 sucessfully 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               |
  
 
   @MissingUsername
   Scenario: Verify error message when username is missing
     
    When User enters username as "" and password as "admin123"
    Then User should be able to see error message "Empty Username"

Step 8 – Create the classes for locators, actions and utilities in src/main/java

Below is the sample code of the LoginPageLocators.

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

	@FindBy(name = "username")
    public WebElement userName;
  
    @FindBy(name = "password")
    public WebElement password;
  
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
    public WebElement login;
  
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
    public  WebElement errorMessage;
     
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
    public WebElement missingUsernameErrorMessage;
       
}

Below is the sample code for the HomePageLocators.

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

	   @FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
	   public  WebElement homePageUserName;
 
}

Create the action classes for each web page. These action classes contain all the methods needed by the step definitions. In this case, I have created 2 action classes – LoginPageActions and HomePageActions .

LoginPageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;

public class LoginPageActions {

	LoginPageLocators loginPageLocators = null; 
	
    public LoginPageActions() {

    	this.loginPageLocators = new LoginPageLocators();

		PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
	}
    
    public void login(String strUserName, String strPassword) {
 
    	loginPageLocators.userName.sendKeys(strUserName);
    	loginPageLocators.password.sendKeys(strPassword);
    	loginPageLocators.login.click();
 
    }
    
    // Get the error message when invalid credentials are provided
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }
    
 
   // Get the error message when username is blank
   public String getMissingUsernameText() {
        return loginPageLocators.missingUsernameErrorMessage.getText();
    }
}

HomePageActions

import org.openqa.selenium.support.PageFactory;

import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;

public class HomePageActions {

	HomePageLocators homePageLocators = null;
   
	public HomePageActions() {
    	
		this.homePageLocators = new HomePageLocators();

		PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }

    // Get the User name from Home Page
    public String getHomePageText() {
        return homePageLocators.homePageUserName.getText();
    }

}

Create a Helper class where we are initializing the web driver, initializing the web driver wait, defining the timeouts, and creating a private constructor of the class, it will declare the web driver, so whenever we create an object of this class, a new web browser is invoked. 

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class HelperClass {
	
	private static HelperClass helperClass;	
	private static WebDriver driver;
    public final static int TIMEOUT = 10;
		
	 private HelperClass() {
		 
			WebDriverManager.chromedriver().setup();
	    	driver = new ChromeDriver();
	        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
	        driver.manage().window().maximize();

	 }      
	    	

    public static void openPage(String url) {
        driver.get(url);
    }

	
	public static WebDriver getDriver() {
		return driver;				
	}
	
	public static void setUpDriver() {
		
		if (helperClass==null) {
			
			helperClass = new HelperClass();
		}
	}
	
	 public static void tearDown() {
		 
		 if(driver!=null) {
			 driver.close();
			 driver.quit();
		 }
		 
		 helperClass = null;
	 } 
	
}

Step 9 – Create the Step Definition class or Glue Code in src/test/java

Now, we need to create the Step Definition of the Feature File – LoginPageDefinitions.java.

import org.testng.Assert;
import org.testng.SkipException;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions {
		
	LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();
		
    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {
    	
    	HelperClass.openPage(url);
 
    }
 
    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {
 
        objLogin.login(userName, passWord);
        
    }
 
    @Then("User should be able to login sucessfully and new page open")
    public void verifyLogin() {
 
        Assert.assertTrue(objHomePage.getHomePageText().contains("Employee Information"));
 
    }
    
    @Then("User should be able to see error message {string}")
    public void verifyErrorMessageForInvalidCredentials(String expectedErrorMessage) {
 
        Assert.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);
 
    }
  
    
    @Then("User should be able to see error message for empty username as {string}")
    public void verifyErrorMessageForEmptyUsername(String expectedErrorMessage) {
    	       Assert.assertEquals(objLogin.getMissingUsernameText(),expectedErrorMessage);
 
    }
 
}

Step 10 – Create a Hook class to contain the initialization and closing of the browser in src/test/java

Below is the example of the Hook class where we initialize the browser as well as close the browser at the end of the execution.

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class BaseClass {

	@Before
    public static void setUp() {

       HelperClass.setUpDriver();
    }


	@After
	public static void tearDown(Scenario scenario) {

		//validate if scenario has failed
		if(scenario.isFailed()) {
			final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
			scenario.attach(screenshot, "image/png", scenario.getName()); 
		}	
		
		HelperClass.tearDown();
	}
}

Step 11 – Create a TestNG Cucumber Runner class in src/test/java

Cucumber needs a TestRunner class to run the feature files. It is suggested to create a folder with the name of the runner in the src/test/java directory and create the Cucumber TestRunner class in this folder. Below is the code of the Cucumber TestRunner class.

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
   
@CucumberOptions(tags = "", features = {"src/test/resources/features/LoginPage.feature"}, glue = {"com.example.definitions"})
   
public class CucumberRunnerTests extends AbstractTestNGCucumberTests {
   
}

Step 12 – Run the tests from Command Line

Run the below command in the command prompt to run the tests and to get the test execution report.

gradle cucumber

The output of the above program is

Step 13 – Cucumber Report Generation

To get Cucumber Test Reports, add cucumber.properties under src/test/resources and add the below instruction in the file.

cucumber.publish.enabled=true

Below is the image of the Cucumber Report generated using the Cucumber Service.

In the above example, as we can see, one of the tests has failed. So, when a test fails, we have written the code to take a screenshot of the failed step. The highlighted box above shows the image of the failed test. You can click on that to see the screenshot.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!