Parallel Testing in Cucumber with TestNG

HOME

In this tutorial, I will explain Parallel Testing using Cucumber with TestNG.

Cucumber-JVM allows parallel execution across multiple threads since version 4.0.0. There are several options to incorporate this built-in feature in a Cucumber project. You can do so by using JUnit, TestNG or CLI.

Cucumber can be executed in parallel using TestNG and Maven test execution plugins by setting the dataprovider parallel option to true.

In TestNG the scenarios and rows in a scenario outline are executed in multiple threads. One can use either Maven Surefire or Failsafe plugin for executing the runners. In this tutorial, I’m using the Maven Surefire plugin.

Pre-Requisite

  1. Java is installed
  2. Maven is installed
  3. TestNG is installed

This framework consists of:

  1. Selenium – 3.141.59
  2. Java 11
  3. Cucumber Java – 6.8.1
  4. Cucumber TestNG- 6.8.1
  5. Maven – 3.8.1
  6. TestNG – 7.4.0
  7. Maven Surefire Plugin – 3.0.0-M5

Steps to create a project for parallel Testing in Cucumber

  1. Create a Maven project.
  2. Update Properties section in Maven pom.xml
  3. Add Cucumber and TestNG dependencies to the project.
  4. Add Surefire plugin configuration to the build section to the POM.
  5. Create 2 feature files under src/test/resources – Login.feature and HomePage.feature.
  6. Create the Step Definition classes for both feature files or Glue Code.
  7. Create a Cucumber TestNG Runner class.
  8. Report Generation
  9. Execute the test from Command Line.
  10. Execute the test from TestNG Runner.
  11. Difference between parallel and non parallel tests

Detailed Step Description

Step 1 – Create a Maven project

Create a Maven project in your favorite IDE using the cucumber-archetype. To know more about this, click here.

Step 2 – Update Properties section in Maven pom.xml

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <selenium.version>3.141.59</selenium.version> 
   <cucumber.version>6.8.1</cucumber.version>
   <testng.version>7.4.0</testng.version>
   <maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
 </properties>

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

Add below mentioned Cucumber-Java and Cucumber-TestNG and Selenium-java dependencies to the project.

<dependencies>

    <!--Cucumber 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 -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

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

</dependencies>
  

Step 4 – Add Surefire plugin configuration to the build section to the POM

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven.surefire.plugin.version}</version>
</plugin>

Step 5 – Create 2 feature files under src/test/resources – Login.feature and HomePage.feature

Below are the sample feature files.

Login.feature

Feature: Login to HRM Application 
 
   @ValidCredentials
   Scenario: Login with valid credentials - Feature 1, Scenario -1
     
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login sucessfully

HomePage.feature

Feature: Home page validation
 
Background:
   Given User Navigates to HRM login page
   And User login with valid credentials

   @ValidQuickLaunch
   Scenario Outline: Login with valid credentials to check QuickLanuch options  - Feature 2, Scenario -1
    
   When User is in Dashboard page
	 Then there are valid QuickLaunch options '<options>'
	  	
	Examples: 
		|options                  |
		|Assign Leave             |
		|Leave List               |

	
	@ValidLegendOptions		
	Scenario Outline: Login with valid credentials to check Manu Options - Feature 2, Scenario -2
    
   When User is in Dashboard page
	 Then there are valid Legend options '<legendOptions>'
	  	
	Examples: 
		|legendOptions               |
		|Administration              |

Step 6 – Create the Step Definition classes for both feature files or Glue Code.

Below is the Step Definition for Login.feature.

public class LoginDefinition {

	WebDriver driver;

	@Given("User is on Home page")
	public void userOnHomePage() {

		System.out.println("Thread ID - " + Thread.currentThread().getId());
		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");

		driver = new FirefoxDriver();

		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@When("User enters username as {string}")
	public void entersUsername(String userName) throws InterruptedException {

		System.out.println("Username Entered");
		driver.findElement(By.name("txtUsername")).sendKeys(userName);

	}

	@When("User enters password as {string}")
	public void entersPassword(String passWord) throws InterruptedException {

		System.out.println("Password Entered");
		driver.findElement(By.name("txtPassword")).sendKeys(passWord);

		driver.findElement(By.id("btnLogin")).submit();
	}

	@Then("User should be able to login sucessfully")
	public void sucessfullLogin() throws InterruptedException {

		String newPageText = driver.findElement(By.id("welcome")).getText();
		System.out.println("newPageText :" + newPageText);
		assertThat(newPageText, containsString("Welcome"));

		driver.quit();

	}

Below is the Step Definition for HomePage.feature.

public class HomePageDefinitions {

	WebDriver driver;

	@Given("User Navigates to HRM login page")
	public void userOnHomePage() {

		System.out.println("Thread ID - " + Thread.currentThread().getId());
		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");

		driver = new FirefoxDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@And("User login with valid credentials")
	public void entersCredentials() throws InterruptedException {
		Thread.sleep(1000);

		driver.findElement(By.name("txtUsername")).sendKeys("Admin");
		driver.findElement(By.name("txtPassword")).sendKeys("admin123");
		driver.findElement(By.id("btnLogin")).submit();

	}

	@When("User is in Dashboard page")
	public void verifyDashboardPage() {

		String dashboardTitle = driver.findElement(By.id("welcome")).getText();
		assertThat(dashboardTitle, containsString("Welcome"));

	}

	@Then("there are valid QuickLaunch options {string}")
	public void verifyQuickLinks(String options) throws InterruptedException {

		switch (options) {
		case "Assign Leave":
			String linkOne = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[1]/div/a/span"))
					.getText();
			Assert.assertEquals(linkOne, options);
			Thread.sleep(1000);
			break;
		case "Leave List ":
			String linkTwo = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[2]/div/a/span"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			Thread.sleep(1000);
			break;
		case "Timesheets":
			String linkThree = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[3]/div/a/span"))
					.getText();
			Assert.assertEquals(linkThree, options);
			Thread.sleep(1000);
			break;
		default:
			break;
		}

		driver.quit();

	}

	@Then("there are valid Legend options {string}")
	public void verifyMenuOptions(String options) throws InterruptedException {

		switch (options) {
		case "Not assigned to Subunits":
			String linkOne = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[1]/td[2]"))
					.getText();
			Assert.assertEquals(linkOne, options);
			Thread.sleep(1000);
			break;
		case "Administration":
			String linkTwo = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[2]/td[2]"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			Thread.sleep(1000);
			break;
		case "Client Services":
			String linkThree = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[3]/td[2]"))
					.getText();
			Assert.assertEquals(linkThree, options);
			Thread.sleep(1000);
			break;
		default:
			break;

		}
		driver.quit();
	}
}

Step 7 – Create a Cucumber TestNG Runner class

Add a cucumber runner by extending the AbstractTestNGCucumberTests class and overriding the scenarios method. Set the parallel option value to true for the DataProvider annotation.

import org.testng.annotations.DataProvider;

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

@CucumberOptions(tags = "", features = "src/test/resources/features", glue = "com.example.Cucumber_TestNGDemo.definitions")

public class CucumberRunnerTests extends AbstractTestNGCucumberTests {

	@Override
	@DataProvider(parallel = true)
	public Object[][] scenarios() {
		return super.scenarios();
	}

}

Step 8 – Report Generation

Add cucumber.properties under src/test/resources and add the below instruction in the file.

cucumber.publish.enabled=true

Step 9 – Execute the test from Command Line

Use the below mentioned command in command prompt to run the tests.

mvn test

Step 10 – Execute the tests from TestNG Runner

Go to Runner class and right click Run As TestNG Test. The tests will run as TestNG tests.

Step 11 – Difference between parallel and non parallel tests

Parallel Tests – All the tests are started at the same time, so they share different threads. The way tests are executed are different in them. With non-paralle tests, all the scenarios of the same feature are executed together and then he scenarios of another feature file. Whereas, in parallel test, all the tests are started at the same time, so there won’t be any specific order.

All the scenarios and rows of the scenario outlines are executed in different threads.

Non Parallel Tests

Parallel Test Report – The execution time to complete the tests are less in parallel test execution as compared to the non parallel one.

Non Parallel Tests Report

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

There is another tutorial which shows Parallel Testing in Cucumber with JUnit.

Integration of Cucumber with Selenium and TestNG

HOME

Cucumber is a BDD Tool and Selenium Webdriver is use for the automation of web application. Imagine we need to build a test framework which can be used by business to understand the test scenarios and as well can test the web application. This can be achieved by integrating Cucumber with Selenium. I’m going to use TestNG as the Test Automation tool for assertions.

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

  1. Cucumber Java- 6.10.4
  2. Cucumber TestNG – 6.10.4
  3. Java 11
  4. TestNG – 7.4.0
  5. Maven – 3.8.1
  6. Selenium – 3.141.59

Steps to setup Cucumber Test Automation Framework with Selenium and TestNG

  1. Download and Install Java on system
  2. Download and setup Eclipse IDE on system
  3. Setup Maven
  4. Create a new Maven Project
  5. Create source folder – src/test/resources to create test scenarios in Feature file
  6. Add Selenium, TestNG and Cucumber dependencies to the project
  7. Add Maven Compiler Plugin
  8. Create a feature file under src/test/resources
  9. Create the Step Definition class or Glue Code
  10. Create a TestNG Cucumber Runner class
  11. Run the tests from TestNG Runner
  12. Run the tests from TestNG.xml
  13. Run the tests from Command Line
  14. Cucumber Report Generation
  15. TestNG Report Generation

Step 1- Download and Install Java

Cucumber and Selenium needs 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 system

The Eclipse IDE (integrated development environment) provides strong support for Java developer 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 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 which is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

Step 4 – 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 – Cucumber_TestNGDemo
Version – 0.0.1-SNAPSHOT
Package – com. example. Cucumber_TestNGDemo

Step 5 – Create source folder src/test/resources to create test scenarios in Feature file

When a new Maven Project is created, it has 2 folders – src/main/java and src/test/java as shown in below image. To create test scenarios, we need a new source folder called – src/test/resources. To create this folder, right click on your maven project ->select New ->Java and then Source Folder.

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

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

 <dependencies>
  <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>6.10.4</version>
    </dependency>
 

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>
    
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>7.4.0</version>
      <scope>test</scope>
    </dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-testng</artifactId>
      <version>6.10.4</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core -->
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest</artifactId>
      <version>2.2</version>
      <scope>test</scope>
    </dependency>
    
</dependencies>

Step 7 – Add Maven Compiler Plugin

The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:

  • compile – compile main source files
  • testCompile – compile test source files
<build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>11</source>
           <target>11</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
       </plugins>
   </build>

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

Feature file should be saved as an extension of .feature. The test scenarios in Feature file are written in Gherkins language. Add the test scenarios in this feature file. I have added sample test scenarios.

Feature: Login to HRM Application 
 
   @ValidCredentials
   Scenario: Login with valid credentials
     
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login sucessfully

Step 9 – Create the stepdefinition class corresponding to the feature file to test the scenarios

public class LoginDefinition {

	WebDriver driver;

	@Before
	public void setUp() {
		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");

		driver = new FirefoxDriver();

		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@Given("User is on Home page")
	public void userOnHomePage() {

		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@When("User enters username as {string}")
	public void entersUsername(String userName) throws InterruptedException {

		System.out.println("Username Entered");
		driver.findElement(By.name("txtUsername")).sendKeys(userName);

	}

	@When("User enters password as {string}")
	public void entersPassword(String passWord) throws InterruptedException {

		System.out.println("Password Entered");
		driver.findElement(By.name("txtPassword")).sendKeys(passWord);

		driver.findElement(By.id("btnLogin")).submit();
	}

	@Then("User should be able to login sucessfully")
	public void sucessfullLogin() throws InterruptedException {

		String newPageText = driver.findElement(By.id("welcome")).getText();
		System.out.println("newPageText :" + newPageText);
		assertThat(newPageText, containsString("Welcome"));

	}

	@After
	public void teardown() {

		driver.quit();
	}

}

assertThat() and containsString are imported from package:-

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;

Step 10 – Create a TestNG Cucumber Runner class to execute the test scenarios

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.

package com.example.Cucumber_TestNGDemo.runner;

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

@CucumberOptions(tags = "", features = "src/test/resources/features/Login.feature", glue = "com.example.Cucumber_TestNGDemo.definitions")

public class CucumberRunnerTest extends AbstractTestNGCucumberTests {

}

  • AbstractTestNGCucumberTests – Runs each cucumber scenario found in the features as separated test.

Step 11 – Test Execution through TestNG

Go to Runner class and right click Run As TestNG Test. The tests will run as TestNG tests.

This is how the execution console will look like.

Step 12 – Run the tests from TestNG.xml

Create a TestNG.xml as shown below and run the tests as TestNG.

<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "Suite1">
  <test name = "Test Demo">
    <classes>
          <class name = "com.example.Cucumber_TestNGDemo.runner.CucumberRunnerTest"/>
     </classes>  
   </test>
</suite>

Step 13 – Run the tests from Command Line

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

mvn test

The execution screen looks like something as shown below.

Step 14 – Cucumber Report Generation

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 Cucumber Service.

Step 15 – TestNG Report Generation

TestNG generates various type of reports under test-output folder like emailable-report.html, index.html, testng-results.xml.

We are interested in ’emailable-report.html’ report. Open ’emailable-report.html’, as this is a html report open it with browser. Below image shows emailable-report.html.

TestNG also produce “index.html” report and it resides under test-output folder. Below image shows index.html report.

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

How To Create Gradle Project with Cucumber to test Rest API

HOME

This tutorial describes the creation of the Gradle Java Project to test Rest API using Cucumber BDD and Rest-Assured.

In this tutorial, I will explain creating a framework for the testing of Rest API in Cucumber BDD. This framework consists of:

  1. Cucumber – 6.8.1 or above
  2. Java 8 or above
  3. JUnit 4
  4. Gradle 6.6.1 (Build Tool)
  5. RestAssured 4.3.3

Steps to setup Gradle Java Project for API Testing using Rest-Assured and Cucumber

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Setup Gradle on System
  4. Create a new Gradle Project
  5. Add Rest-Assured and Cucumber dependencies to the Gradle project
  6. Add Configuration to build.gradle
  7. Add Gradle Cucumber Task to build.gradle
  8. Create a feature file under src/test/resources
  9. Create the Step Definition class or Glue Code for the Test Scenario
  10. Create a Cucumber Runner class
  11. Run the tests from JUnit
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Project Structure

Step 1- Download and Install Java

Cucumber and Rest-Assured 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 system

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

Step 3 – Setup Gradle

To build a test framework, we need to add several dependencies to the project. This can be achieved by any build Tool. I have used Gradle Build Tool. Click here to know How to install Gradle.

Step 4 – Create a new Gradle Project

File -> New Project-> Gradle -> Gradle project-> Next -> Enter Project Name and Project Location ->Next ->Select Gradle Version ->Next ->Review the Configuration -> Finish

Click here to know How to create a Gradle Java project. Below is the structure of Gradle project.

Step 5 – Add Rest-Assured and Cucumber dependencies to the Gradle project. 

This syntax is used for Gradle 5.0 and higher.

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:29.0-jre'
    
    testImplementation 'io.cucumber:cucumber-java:6.8.1'
    testImplementation 'io.cucumber:cucumber-junit:6.8.1'
    testImplementation 'io.rest-assured:rest-assured:4.3.3'

If you are using Gradle 4.10.3 or older, use the below dependency block to build.gradle.

dependencies {
    testCompile 'io.cucumber:cucumber-java:6.8.1'
}

Step 6 – Add Configuration to build.gradle

Below configuration is added to build.gradle when Gradle is 5.0 or higher version.

configurations {
    cucumberRuntime {
        extendsFrom testImplementation
    }
}

If Gradle is 4.10.3 or older, use the below configuration.

configurations {
    cucumberRuntime {
        extendsFrom testRuntime
    }
}

Step 7 – Add Gradle Cucumber Task to build.gradle 

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.gradle.apidemo', 'src/test/resources']
        }
    }
}

Once you have added dependencies, configurations and gradle cucumber task, Right click on the project, Hover to Gradle option and click Refresh Gradle Project. Eclipse does not automatically update the classpath, if the build.gradle file is updated. Select Gradle  Refresh Gradle Project from the context menu of the project or from your build.gradle file for that.

Step 8 – Create a feature file under src/test/resources

A new Gradle Project is created with 4 folders – src/main/java , src/main/resources, src/test/java and src/test/resources. Features are created under 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 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 a Test Scenario where we are using the GET method to get the information from the API.

Feature: Validation of get method
 
@GetUserDetails
  Scenario Outline: Send a valid Request to get user details
 
  Given I send a request to the URL to get user details
  Then the response will return status 200 and id <id> and salary <employee_salary> and name "<employee_name>" and age <employee_age> and message "<message>"
 
Examples:
    |id  |employee_salary|employee_name |employee_age  |message                                  |
    |1   |320800         |Tiger Nixon   |61            |Successfully! Record has been fetched.   |
   

Step 9 – Create the Step Definition class or Glue Code for the Test Scenario

StepDefinition acts as an intermediate to your runner and feature file. It stores the mapping between each step of the scenario in the Feature file. So when you run the scenario, it will scan the stepDefinition file to check matched glue or test code.

import io.restassured.http.ContentType;
 
import io.restassured.response.ValidatableResponse;
 
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
 
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
 
public class API_GETDefinitions {
     
 
    private ValidatableResponse validatableResponse;
 
    private String endpoint = "http://dummy.restapiexample.com/api/v1/employee/1";
  
    @Given("I send a request to the URL to get user details")
    public void sendRequest(){
        validatableResponse = given().contentType(ContentType.JSON)
                .when().get(endpoint).then();   
         
        System.out.println("Response :"+validatableResponse.extract().asPrettyString());
    }
  
  
    @Then("the response will return status {int} and id {int} and salary {int} and name {string} and age {int} and message {string}")
    public void verifyStatus(int statusCode, int id, int emp_Salary, String emp_name, int emp_age, String message ){
         
        validatableResponse.assertThat().statusCode(statusCode);
         
        validatableResponse.assertThat().body("data.id",equalTo(id));
         
        validatableResponse.assertThat().body("data.employee_salary",equalTo(emp_Salary));
         
        validatableResponse.assertThat().body("data.employee_name",equalTo(emp_name));
         
        validatableResponse.assertThat().body("data.employee_age",equalTo(emp_age));
         
        validatableResponse.assertThat().body("message",equalTo(message));      
         
    }
}

In order to use REST assured effectively it’s recommended to statically import methods from the following classes:

import io.restassured.RestAssured.*
import io.restassured.matcher.RestAssuredMatchers.*
import static org.hamcrest.Matchers.*

given() method is imported from package:

import static io.restassured.RestAssured.given;

equalTo() method is imported from package:

import static org.hamcrest.Matchers;

Step 10 – Create a Cucumber Runner class 

A runner will help us to run the feature file and acts as an interlink between the feature file and StepDefinition Class. To know more about Runner, refer this link.

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)

@CucumberOptions(plugin ="pretty",features= {"src/test/resources/features/API_GET.feature"}, glue= {"com.example.gradle.apidemo"})

public class CucumberRunnerTest {

}

Step 11 – Run the tests from JUnit

You can execute the test script by right-clicking on TestRunner class -> Run As JUnit.

Step 12 – Run the tests from Command Line

Run the following gradle task from the directory path where build.gradle file is located. To know more about this report, refer here.

gradle cucumber

Below is the screenshot of the execution of Cucumber tests in Command Line.

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.

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

Rest API Test in Cucumber BDD

HOME

Cucumber is not an API automation tool, but it works well with other API automation tools.

There are 2 most commonly used Automation Tools for JVM to test API – Rest-Assured and Karate. In this tutorial, I will use RestAssured for API Testing.

What is Rest Assured?

REST Assured is a Java library that provides a domain-specific language (DSL) for writing powerful, maintainable tests for RESTful APIs. REST Assured can be used easily in combination with existing unit testing frameworks, such as JUnit and TestNG.

What is Cucumber?

Cucumber is one such open-source tool, which supports Behavior Driven Development(BDD). In simple words, Cucumber can be defined as a testing framework, driven by plain English. It serves as documentation, automated tests, and development aid – all in one.

In this tutorial, I will explain creating a framework for the testing of Rest API in Cucumber BDD. This framework consists of:

  1. Cucumber
  2. Java 8 or above
  3. JUnit
  4. Maven
  5. RestAssured

Steps to setup Cucumber Test Automation Framework for API Testing using Rest-Assured

  1. Download and Install Java on the system
  2. Download and setup Eclipse IDE on the system
  3. Setup Maven on System
  4. Create a new Maven Project
  5. Create a source folder – src/test/resources to create test scenarios in the Feature file
  6. Add Rest-Assured and Cucumber dependencies to the project
  7. Add Maven Compiler Plugin
  8. Create a feature file under src/test/resources
  9. Create the Step Definition class or Glue Code for the Test Scenario
  10. Create a Cucumber Runner class
  11. Run the tests from JUnit
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Project Structure

Step 1- Download and Install Java

Cucumber and Rest-Assured 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 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 several dependencies to the project. Click here to know How to install Maven.

Step 4 – Create a new Maven Project

File -> New Project-> Maven-> Maven project-> Next -> Enter Group ID & Artifact ID -> Finish

Click here to know How to create a Maven project

Step 5 – Create source folder src/test/resources to create test scenarios in Feature file

A new Maven Project is created with 2 folders – src/main/java and src/test/java. To create test scenarios, we need a new source folder called – src/test/resources. To create this folder, right-click on your maven project ->select New ->Java and then Source Folder.

Mention the source folder name as src/test/resources and click the Next button. This will create a source folder under your new Maven project as shown in the below image.

Step 6 – Add Rest-Assured and Cucumber dependencies to the project

You should place rest-assured before the JUnit dependency declaration in your pom.xml / build.gradle to make sure that the correct version of Hamcrest is used.
REST Assured includes JsonPath and XmlPath as transitive dependencies.

<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>4.3.3</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
<dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>6.8.1</version>
      <scope>test</scope>
</dependency>
  
<dependency>
	  <groupId>io.cucumber</groupId>
	  <artifactId>cucumber-java</artifactId>
	  <version>6.8.1</version>
	  <scope>test</scope>
</dependency>

<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
</dependency>

Step 7 – Add Maven Compiler Plugin

The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:

  • compile – compile main source files
  • testCompile – compile test source files
<build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
     </plugins>
</build>

Step 8 – Create a feature file under src/test/resources

Create a folder with name features. Now, create the feature file in this folder. The feature file should be saved with 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 a Test Scenario where we are using the GET method to get the information from the API.

Feature: Validation of get method

@GetUserDetails
  Scenario Outline: Send a valid Request to get user details

  Given I send a request to the URL to get user details
  Then the response will return status 200 and id <id> and salary <employee_salary> and name "<employee_name>" and age <employee_age> and message "<message>"

Examples:
    |id  |employee_salary|employee_name |employee_age  |message                                  |
    |1   |320800         |Tiger Nixon   |61            |Successfully! Record has been fetched.   |
   

Step 9 – Create the Step Definition class or Glue Code for the Test Scenario

StepDefinition acts as an intermediate to your runner and feature file. It stores the mapping between each step of the scenario in the Feature file. So when you run the scenario, it will scan the stepDefinition file to check matched glue or test code.

import io.restassured.http.ContentType;

import io.restassured.response.ValidatableResponse;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

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

public class API_GETDefinitions {
	

	private ValidatableResponse validatableResponse;

    private String endpoint = "http://dummy.restapiexample.com/api/v1/employee/1";
 
	@Given("I send a request to the URL to get user details")
	public void sendRequest(){
		validatableResponse = given().contentType(ContentType.JSON)
			    .when().get(endpoint).then();   
		
		System.out.println("Response :"+validatableResponse.extract().asPrettyString());
	}
 
 
	@Then("the response will return status {int} and id {int} and salary {int} and name {string} and age {int} and message {string}")
	public void verifyStatus(int statusCode, int id, int emp_Salary, String emp_name, int emp_age, String message ){
		
		validatableResponse.assertThat().statusCode(statusCode);
		
		validatableResponse.assertThat().body("data.id",equalTo(id));
		
		validatableResponse.assertThat().body("data.employee_salary",equalTo(emp_Salary));
		
		validatableResponse.assertThat().body("data.employee_name",equalTo(emp_name));
		
		validatableResponse.assertThat().body("data.employee_age",equalTo(emp_age));
		
		validatableResponse.assertThat().body("message",equalTo(message));		
		
	}
}

In order to use REST assured effectively it’s recommended to statically import methods from the following classes:

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*

There is another way to perform these assertions. We can use multiple body assertions together.

@Then("the response will return status {int} and id {int} and salary {int} and name {string} and age {int} and message {string}")
	public void verifyStatus(int statusCode, int id, int emp_Salary, String emp_name, int emp_age, String message ){
				

validatableResponse.assertThat().statusCode(statusCode).body("data.id",equalTo(id)).and()
		.body("data.employee_salary",equalTo(emp_Salary)).body("data.employee_name",equalTo(emp_name))
		.body("data.employee_age",equalTo(emp_age)).body("message",equalTo(message));

Step 10 – Create a JUnit Cucumber Runner class to execute the test scenarios

A runner will help us to run the feature file and acts as an interlink between the feature file and StepDefinition Class.

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)

@CucumberOptions(features= {"src/test/resources"}, glue= {"com.example.apidemo"})
public class CucumberRunnerTest {

}

Note:- The name of the Runner class should end with Test otherwise we can’t run the tests using Command-Line.

Step 11 – Run the tests from JUnit

You can execute the test script by right-clicking on TestRunner class -> Run As JUnit.

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.

mvn test

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

Conditional Hooks in Cucumber

HOME

In the previous tutorial, I have explained Hooks in Cucumber. In this tutorial, I will explain Condition Hooks in Cucumber.

Hooks can be conditionally selected for execution based on the tags of the scenario. These are called Condition or Tagged Hooks.

Tagged Hooks are much like the scenario hooks, but the only difference is that they are executed before and after the specified tag.

These Tagged hooks will be very specific to the particular tags, so these are not common for all scenarios.

So basically, they can also be run in the following two ways:

  • Before (‘tagName’)
  • After (‘tagName’)

Why do we need Tagged Hooks?

Suppose there are 3 different sets of scenarios. The pre-requisite of these scenarios are different like they have to open different browsers. So, we don’t want to have a common hook for all the scenarios. In this case, we can create a tagged hook to satisfy the requirement of each scenario.

In the below example, there are 3 tags – ChromeBrowser, FireFoxBrowser, and EdgeBrowser. I want to run the hook which has the specified tag for that scenario. For Example, I want @After and @Before hooks related to Chrome Browser should be executed for tag – @ChromeBrowser.

Below is the feature file which has 3 different scenarios.

Feature: Conditional or Tagged Hooks
 
@ChromeBrowser
Scenario: Open Chrome Browser
 
Given I want to open Google Chrome Browser

@FireFoxBrowser
Scenario: Open Firefox Browser
 
Given I want to open Mozilla Firefox Browser

@EdgeBrowser
Scenario: Open Edge Browser
 
Given I want to open Microsoft Edge Browser

Below is the Step Definition for above feature file.

package com.Cucumber;

import cucumber.api.java.en.Given;

public class ConditionalHooksExampleDefinitions {
	
	@Given("I want to open Google Chrome Browser")
	public void chrome() throws Throwable {
	    System.out.println("I want to open Google Chrome Browser");
	}

	@Given("I want to open Mozilla Firefox Browser")
	public void firefox() throws Throwable {
		System.out.println("I want to open Mozilla Firefox Browser");
	}

	@Given("I want to open Microsoft Edge Browser")
	public void edge() throws Throwable {
		System.out.println("I want to open Microsoft Edge Browser");
	}

}

Hooks can be defined in the same class or different. I have defined Hooks in a seperate class.

package com.Cucumber;

import cucumber.api.java.After;
import cucumber.api.java.Before;

public class Hooks {
	
	@BeforeStep
    public void beforeStep(){
        System.out.println("@@@@@@@@@@@@@@@ Before Step @@@@@@@@@@@@@@@@@");
    }
	
	@AfterStep
    public void afterStep(){
        System.out.println("@@@@@@@@@@@@@@@@  After Step @@@@@@@@@@@@@@@@");
    }
	
	@Before("@ChromeBrowser")
    public void beforeGoogle(){
        System.out.println("******* before Chrome *******");
    }
	
	@Before("@FireFoxBrowser")
    public void beforeFirefox(){
        System.out.println("$$$$$$$$$$ before FireFox $$$$$$$$$$");
    }

	@Before("@EdgeBrowser")
    public void beforeEdge(){
		System.out.println("============ before Edge =============");
    }
	
	@After("@ChromeBrowser")
    public void afterGoogle(){
        System.out.println("********* After Google *********");
    }

	@After("@FireFoxBrowser")
    public void afterFireFox(){
		System.out.println("$$$$$$$$$$$ After FireFox $$$$$$$$$$");
    }

	@After("@EdgeBrowser")
    public void afterEdge(){
        System.out.println("============ After Edge ==============");
    }

}

There is no change in the Test Runner Class.

package com.Cucumber;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(monochrome = true, plugin = "pretty", features = "src/test/resources/features/ConditionalHooksExample.feature", tags = {
		"" })
public class MyRunner {

}

Execution Result looks like something below

  1. At the start of execution, @Before(“@ChromeBrowser”) {Scenario Hook} is executed.
  2. After that @BeforeStep (Step Hook) hook is executed.
  3. Given statement of @ChromeBrowser tag is executed in the third step.
  4. Fourth Step is to execute @AfterStep.
  5. Now at the last, @After(“@ChromeBrowser”) hook is executed. Similarly, same sequence is followed for FireFox and Edge Scenarios.

Parallel Testing in Cucumber with JUnit

HOME

In this tutorial, I will explain Parallel Testing using Cucumber with JUnit.

Cucumber-JVM allows parallel execution across multiple threads since version 4.0.0. There are several options to incorporate this built-in feature in a Cucumber project. You can do so by using JUnit, TestNG or CLI.

Cucumber can be executed in parallel using JUnit and Maven test execution plugins.

In JUnit, the feature files are run in parallel rather than scenarios, which means all the scenarios in a feature file will be executed by the same thread. You can use either Maven Surefire or Failsafe plugin to execute the runner. In this tutorial, I’m using the Maven Surefire plugin.

This framework consists of:-

  1. Cucumber Java- 6.8.1
  2. Cucumber JUnit – 6.8.1
  3. Java 11
  4. JUnit– 4.13.2
  5. Maven – 3.8.1
  6. Selenium – 3.141.59
  7. Maven Surefire Plugin – 3.0.0-M5

Steps to create a project for parallel Testing in Cucumber

  1. Create a Maven project.
  2. Add Cucumber and JUnit dependencies to the project.
  3. Add Surefire plugin configuration to the build section to the POM.
  4. Create a feature file under src/test/resources.
  5. Create the Step Definition class or Glue Code.
  6. Create a Cucumber Runner class.
  7. Execute the test from Command Line.
  8. Generate Cucumber Report.

Detailed Step Description

Step 1 – Create a Maven project

Create a Maven project in your favorite IDE using the cucumber-archetype or by adding Cucumber dependencies to the POM as detailed here and Junit dependencies here. To know more about this, click here.

Below is the structure of project.

Step 2 – Update Properties section in Maven pom.xml

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <selenium.version>3.141.59</selenium.version> 
   <cucumber.version>6.8.1</cucumber.version>
   <junit.version>4.13.2</junit.version>
   <maven.surefire.plugin.version>3.0.0-M5</maven.surefire.plugin.version>
 </properties>

Step 2 – Add Cucumber and JUnit dependencies to the project

Add below mentioned Cucumber-Java and Cucumber-JUnit dependencies to the project.

<dependencies>

   <!-- Cucumber Dependencies -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>
  
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
     </dependency>

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

    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency

</dependencies>
  

Step 3 – Add Surefire plugin configuration to the byuld section to the POM.

 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven.surefire.plugin.version}</version>
   <configuration>
        <parallel>methods</parallel>
        <useUnlimitedThreads>true</useUnlimitedThreads>
        <testFailureIgnore>true</testFailureIgnore>
	</configuration>
</plugin> 

To set the thread count to a specific number instead of useUnlimitedThreads use the below setting.

<configuration>
    <parallel>methods</parallel>
    <threadCount>4</threadCount>
</configuration>

The thread count in the above setting is 4 threads per core.

Step 4 – Create a feature folder under src/test/resources

Add 4 feature files – FlightBooking.feature, TrainBooking.feature, HomePage.feature and Login.feature

FlightBooking.feature

Feature: Book flight ticket 
 
@BookOneWayFlight
Scenario: Book Flight for one way trip
 
Given I want to book one way flight ticket from Dublin to London on 22nd July for 2 adults and 2 kids
Then TripAdvisor should provide me options to book flight ticket

@BookRoundTripFlight
Scenario: Book Flight for round trip
 
Given  I want to book roundtrip flight ticket from Dublin to India on 30th June and return 10th July for 2 adults and 1 kid
Then TripAdvisor should provide me options to book flight ticket 

TrainBooking.feature

Feature: Book Train Ticket
 
@BookOneWayTrain
Scenario: Book train ticket for one way
 
Given I want to book one way train ticket from Dublin to Cork on 10th June for 2 adults and 2 kids
Then IrishRail should provide me options to book train ticket for the specified date

HomePage.feature

Feature: Home page validation
  
Background:
   Given User Navigates to HRM login page
   And User login with valid credentials
 
   @ValidQuickLaunch
   Scenario Outline: Login with valid credentials to check QuickLanuch options  - Feature 2, Scenario -1
     
   When User is in Dashboard page
     Then there are valid QuickLaunch options '<options>'
         
    Examples: 
        |options                  |
        |Assign Leave             |
        |Leave List               |
 
     
    @ValidLegendOptions    
    Scenario Outline: Login with valid credentials to check Manu Options - Feature 2, Scenario -2
     
   When User is in Dashboard page
     Then there are valid Legend options '<legendOptions>'
         
    Examples: 
        |legendOptions               |
        |Administration              |

Login.feature

Feature: Login to HRM Application 
  
   @ValidCredentials
   Scenario: Login with valid credentials - Feature 1, Scenario -1
      
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login sucessfully

Step 5 – Create the Step Definition class or Glue Code

Below is the Step Definition for FlightBooking.feature.

public class FlightBookingDefinitions {
	
	@Given("I want to book one way flight ticket from Dublin to London on 22nd July for 2 adults and 2 kids")
	   public void singleTrip(){
	        System.out.println("I want to book one way flight ticket from Dublin to London on 22nd July for 2 adults and 2 kids");
	   }
	 
	@Then("TripAdvisor should provide me options to book flight ticket")
	   public void TripAdvisor(){
	        System.out.println("TripAdvisor should provide me options to book flight ticket");
	   }
	
	@Given("I want to book roundtrip flight ticket from Dublin to India on 30th June and return 10th July for 2 adults and 1 kid")
	   public void roundTrip(){
	        System.out.println("I want to book one way flight ticket from Dublin to London on 22nd July for 2 adults and 2 kids");
	   }
}

Below is the StepDefinition for TrainBooking.feature.

public class TrainBookingDefinitions {

	@Given("I want to book one way train ticket from Dublin to Cork on 10th June for 2 adults and 2 kids")
	   public void hotelWithoutBreakfast(){
	        System.out.println("I want to book one way train ticket from Dublin to Cork on 10th June for 2 adults and 2 kids");
	   }
	 
	@Then("IrishRail should provide me options to book train ticket for the specified date")
	   public void Trivago(){
	        System.out.println("IrishRail should provide me options to book train ticket for the specified date");
	   }

}

Below is the StepDefinition for Login.feature.

public class LoginDefinition {

	WebDriver driver;

	@Given("User is on Home page")
	public void userOnHomePage() {

		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");

		driver = new FirefoxDriver();

		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@When("User enters username as {string}")
	public void entersUsername(String userName) throws InterruptedException {

		System.out.println("Username Entered");
		driver.findElement(By.name("txtUsername")).sendKeys(userName);

	}

	@When("User enters password as {string}")
	public void entersPassword(String passWord) throws InterruptedException {

		System.out.println("Password Entered");
		driver.findElement(By.name("txtPassword")).sendKeys(passWord);

		driver.findElement(By.id("btnLogin")).submit();
	}

	@Then("User should be able to login sucessfully")
	public void sucessfullLogin() throws InterruptedException {

		String newPageText = driver.findElement(By.id("welcome")).getText();
		System.out.println("newPageText :" + newPageText);
		Assert.assertTrue(newPageText.contains("Welcome"));

		driver.quit();

	}
}

Below is the StepDefinition for HomePage.feature.

public class HomePageDefinition {

	WebDriver driver;

	@Given("User Navigates to HRM login page")
	public void userOnHomePage() {

		System.setProperty("webdriver.gecko.driver",
				"C:\\Users\\Vibha\\Software\\geckodriver-v0.26.0-win64\\geckodriver.exe");

		driver = new FirefoxDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@Given("User login with valid credentials")
	public void entersCredentials() throws InterruptedException {
		Thread.sleep(1000);

		driver.findElement(By.name("txtUsername")).sendKeys("Admin");
		driver.findElement(By.name("txtPassword")).sendKeys("admin123");
		driver.findElement(By.id("btnLogin")).submit();

	}

	@When("User is in Dashboard page")
	public void verifyDashboardPage() {

		String dashboardTitle = driver.findElement(By.id("welcome")).getText();
		Assert.assertTrue(dashboardTitle.contains("Welcome"));

	}

	@Then("there are valid QuickLaunch options {string}")
	public void verifyQuickLinks(String options) throws InterruptedException {

		switch (options) {
		case "Assign Leave":
			String linkOne = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[1]/div/a/span"))
					.getText();
			Assert.assertEquals(linkOne, options);
			Thread.sleep(1000);
			break;
		case "Leave List ":
			String linkTwo = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[2]/div/a/span"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			Thread.sleep(1000);
			break;
		case "Timesheets":
			String linkThree = driver
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[3]/div/a/span"))
					.getText();
			Assert.assertEquals(linkThree, options);
			Thread.sleep(1000);
			break;
		default:
			break;
		}

		driver.quit();

	}

	@Then("there are valid Legend options {string}")
	public void verifyMenuOptions(String options) throws InterruptedException {

		switch (options) {
		case "Not assigned to Subunits":
			String linkOne = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[1]/td[2]"))
					.getText();
			Assert.assertEquals(linkOne, options);
			Thread.sleep(1000);
			break;
		case "Administration":
			String linkTwo = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[2]/td[2]"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			Thread.sleep(1000);
			break;
		case "Client Services":
			String linkThree = driver
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[3]/td[2]"))
					.getText();
			Assert.assertEquals(linkThree, options);
			Thread.sleep(1000);
			break;
		default:
			break;

		}
		driver.quit();
	}
}

Step 6 – Create a Test Runner to run the tests

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)

@CucumberOptions(features= {"src/test/resources"}, glue= {"com.cucumber.parallel_demo"})
public class RunCucumberTest {

}

Step 7 – Execute the tests from command line

mvn test

Below is the execution screen. There are four feature files. Out of four files, two are simple feature files (FlightBooking and TrainBooking ) whereas another two Feature files are complex (Login and Home). These feature file contains the below number of scenarios.

FlightBooking – 2 Scenarios
TrainBooking – 1 Scenario
Login – 1 Scenario
Home – 4 Scenarios

Feature files are executed in alphabetical order. So, the sequence in which non-parallel tests will run is FlightBooking -> Home ->Login -> TrainBooking

But, as we have executed tests parallelly, so the feature files will run in this order (depending on the least number of scenarios will be executed first) TrainBooking -> FlightBooking -> Login -> Home

All the tests of a particular feature file are executed together as feature files are run in parallel, not scenarios.

Step 8 – 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 Cucumber Service.

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

In the next tutorial, I have explained about Parallel Testing in Cucumber with TestNG.

DataTables in Cucumber

HOME

Cucumber Data Tables can be used to add multiple parameters in Step Definition in a tabular form rather than putting all the parameters in the Gherkin statement. This is much easier to read and multiple rows of data can be passed in the same step. Data tables from Gherkin can be accessed by using the DataTable object as the last parameter in a Step Definition. This conversion can be done either by Cucumber or manually.

Depending on the table shape we can use one of the following collections:

List<List<String>> table
List<Map<String, String>> table
Map<String, String> table
Map<String, List<String>> table
Map<String, Map<String, String>> table

Let’s write a simple data table and see how we might use it.

  1. Table into List of a List of Strings
| firstName | lastName | age |
| Thomas | Brown | 30 |
| Perry | Wilson | 26 |
| Ashley | William | 27 |

java type: List<List<String>>

The natural representation of list of a list of strings is shown below.

[ 
  [ "firstName", "lastName", "age" ],
  [ "Thomas", "Brown", "30" ], 
  [ "Perry", "Wilson", "26" ], 
  [ "Ashley", "William", "27" ] 
]

2. Table into List of Maps

java type: List<Map<String, String>>
The natural representation of list of maps is shown below.

[
  { "firstName": "Thomas", "lastName": "Brown",  "age": "30" }, 
  { "firstName": "Perry",  "lastName": "Wilson", "age": "26" }, 
  { "firstName": "Ashley", "lastName": "William", "age": "27" } 
]

3. Table into Single Map

Table where first colum is key as shown below

| IN  | India          |
| IRE | Ireland        |
java type: Map<String, String>

TO convert the table into a single map

{
  "IN": "India",
  "IRE": "Ireland"
}

4. Table into map that uses a list as its value

 A table with multiple column values per key.
 
 | IN  | India          | 29  |
 | IRE | Ireland        | 8   |

java type: Map<String, List<String>>

{
  "IN":  ["India","29"],
  "IRE": ["Ireland","8"]
}

Now, let us see how we can use DataTable in Cucumber

Cucumber Data Tables Example in Java

Data Table without Header Example

Below is an example of how to implement Data Tables without a Header. For example, we want to test the Login Page of an application. We can either mention all the arguments inside the Gherkin statement or use a table to list all the arguments as we used below:

Feature: Login to HRM Application 
 
   @ValidCredentials
   Scenario: Login with valid credentials
     
    Given User is on HRMLogin page
    When User enters valid credentials
    |Admin|admin123|
    Then User should be able to login sucessfully and new page open

Below is the Step Definition of the above scenario.

public class LoginDefinitions {

	 WebDriver driver;
	 
	 @Before
	 public void setup() {
	 
		 System.setProperty("webdriver.gecko.driver",
	                "C:\\Users\\Vibha\\Desktop\\Drivers\\geckodriver-v0.26.0-win64\\geckodriver.exe");
	        driver = new FirefoxDriver();
	        driver.manage().window().maximize();
	        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	 }
	 
	  @Given("User is on HRMLogin page")
	  public void userOnHomePage() {
	        
	        driver.get("https://opensource-demo.orangehrmlive.com/");
	  }
	 
	  @When("User enters valid credentials")
	  public void entersValidCredential(DataTable dataTable) throws InterruptedException{
	 
	        System.out.println("Credentials Entered");	        
	        List<String> signUpForm = dataTable.asList();	        
	        String userName = signUpForm.get(0);
	        String passWord = signUpForm.get(1);          
	        driver.findElement(By.name("txtUsername")).sendKeys(userName);
	        driver.findElement(By.name("txtPassword")).sendKeys(passWord);       
	        driver.findElement(By.id("btnLogin")).submit();
	  }
	    
	 
	  @Then("User should be able to login sucessfully and new page open")
	  public void sucessfullLogin() throws InterruptedException {
	 
	        String newPageText = driver.findElement(By.id("welcome")).getText();
	        System.out.println("newPageText :" + newPageText);
	        assertThat(newPageText, containsString("Welcome"));         
	  }
	   
	    
	  @After
	  public void teardown(){
	    	 driver.close();
	  }
}

In the above example, as we don’t have a header, we have just got the List object and get the values of DataTable starting from 0 index.

Cucumber converts the above table into a list of lists by treating each row as a list of the column values. We use the asLists method — supplying a String.class argument — to convert the DataTable argument to a List<List<String>>This Clasargument informs the asLists method of what data type we expect each element to be.

Data Table with Header and Single Row Example

Below is a cucumber data tables example with the header. Adding a header to your table makes it easier to read and maintain.

   @InValidCredential
   Scenario: Login with valid credentials
     
   Given User is on HRMLogin page
   When User enters invalid credentials and Login will be unsuccessfull with error message
   |Username  |Password  | ErrorMessage      |              
   |Admin1    |admin123!|Invalid credentials |

Below is the Step Definition of above scenario.

  @When("User enters invalid credentials and Login will be unsuccessfull with error message")
	    public void entersInvalidCredentials(DataTable userTable) throws InterruptedException {
	 
	        System.out.println("Enter Credentials");	                
	        List<Map<String, String>> user = userTable.asMaps(String.class, String.class);
	      
	        String userName = user.get(0).get("Username");	        		
	        System.out.println("Username :" + userName);
	        
	        String passWord = user.get(0).get("Password");
	        System.out.println("Password :" + passWord);
	        driver.findElement(By.name("txtPassword")).sendKeys(passWord);	        
	        driver.findElement(By.id("btnLogin")).submit();
	       
	        String errorMessage = user.get(0).get("ErrorMessage");        
	        String actualErrorMessage = driver.findElement(By.id("spanMessage")).getText();	        
            System.out.println("Actual Error Message :" + actualErrorMessage);
	        Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));       
	 
	    }

In the above example, we have only 1 row with the header, so have used get(0) to retrieve the first row of DataTable. After that, I have used get(“HeaderName”) to get the value of the row of DataTable.

Data Table with Header and Multiple Rows Example

Below is a cucumber data tables example with multiple rows of data with the header. This is helpful when we want to test multiple combinations of data in a step.

 @InValidCredentials
   Scenario: Login with valid credentials
     
    Given User is on HRMLogin page
    When User enters invalid credentials and Login will be unsuccessfull with error message
    |Username    |Password  | ErrorMessage       |
    |Admin1      |admin123!|Invalid credentials  |
    |Admina      |admin123a|Invalid credentials  |
   

Below is the Step Definition of the above scenario

  @When("User enters invalid credentials and Login will be unsuccessfull with error message")
	    public void entersInvalidCredentials(DataTable userTable) throws InterruptedException {
	 
	        System.out.println("Enter Credentials");                
	        
	        List<Map<String, String>> user = userTable.asMaps(String.class, String.class);       
	        for (Map<String, String> form : user) {
	        
	        String userName = form.get("Username");
	        System.out.println("Username :" + userName);
	        driver.findElement(By.name("txtUsername")).sendKeys(userName);

	        String passWord = form.get("Password");
	        System.out.println("Password :" + passWord);
	        driver.findElement(By.name("txtPassword")).sendKeys(passWord);    
	  
	        driver.findElement(By.id("btnLogin")).submit();     
	          
            String errorMessage = form.get("ErrorMessage");
	        String actualErrorMessage = driver.findElement(By.id("spanMessage")).getText();
	        System.out.println("Actual Error Message :" + actualErrorMessage);
	 
	        Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));
	      
	        }         
	    }

Cucumber creates a list containing each row but instead maps the column heading to each column value. Cucumber repeats this process for each subsequent row. We use the asMaps method — supplying two String.class arguments — to convert the DataTable argument to a List<Map<String, String>>.

The first argument denotes the data type of the key (header) and the second indicates the data type of each column value. Thus, we supply two String.class arguments because our headers (key) and title and author (values) are all Strings.

That’s it! We are done!!!

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

Page Object Model with Selenium and Cucumber

HOME

In this tutorial, I’ll create a BDD Framework for the testing of web applications using Page Object Model . This framework consists of

  1. Cucumber Java – 6.8.1
  2. Cucumber JUnit4 – 6.8.1
  3. Java 11
  4. Maven – 3.8.1
  5. Selenium – 3.141.59

What Is Page Object Model (POM)?

Page Object model is an object design pattern in Selenium, where web pages are represented as classes, and the various elements on the page are defined as variables in the class and all possible user interactions can then be implemented as methods in the class.

What is Cucumber?

Cucumber is one such open source tool, which supports Behavior Driven Development(BDD). In simple words, Cucumber can be defined as a testing framework, driven by plain English. It serves as documentation, automated tests, and a development aid – all in one.

Steps to setup Cucumber Test Automation Framework using Page Object Model

  1. Download and Install Java on system
  2. Download and setup Eclipse IDE on system
  3. Setup Maven on System
  4. Create a new Maven Project
  5. Create a source folder – src/test/resources to create test scenarios in Feature file
  6. Add Selenium and Cucumber dependencies to the project
  7. Add Maven Compiler Plugin
  8. Create a feature file under src/test/resources
  9. Create the Step Definition class or Glue Code for the Test Scenarios
    1. Create a Java Class for each page where define WebElements as variables using Annotation @FindBy and Create methods for actions performed on WebElements.
    2. Create a Java Class called Definition where we will create the Test Code related to Given,When, Then of Feature file
  10. Create a Cucumber Runner class
  11. Run the tests from JUnit
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Project Structure

Step 1- Download and Install Java

Cucumber and Selenium needs 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 system

The Eclipse IDE (integrated development environment) provides strong support for Java developer. 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 – Create a new Maven Project

File -> New Project-> Maven-> Maven project-> Next -> Enter Group ID & Artifact ID -> Finish

Click here to know How to create a Maven project

Step 5 – Create source folder src/test/resources to create test scenarios in Feature file

A new Maven Project is created with 2 folders – src/main/java and src/test/java. To create test scenarios, we need a new source folder called – src/test/resources. To create this folder, right click on your maven project ->select New ->Java and then Source Folder.

Mention the source folder name as src/test/resources and click Next button. This will create a source folder under your new Maven project as shown in the below image.

Step 6 – Add Selenium and Cucumber dependencies to the project

Add below mentioned Selenium and Cucumber dependencies to the project.

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>6.8.1</version>
    </dependency>
 
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>6.8.1</version>
      <scope>test</scope>
     </dependency>
 
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>

Step 7 – Add Maven Compiler Plugin

The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:

  • compile – compile main source files
  • testCompile – compile test source files
<build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>11</source>
           <target>11</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
       </plugins>
   </build>

Step 8 – Create a feature file under src/test/resources

Create a folder with name features. Now, create the feature file in this folder. The feature file should be saved with extension .feature. This feature file contain 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 Test Scenario in feature file.

Feature: Login to HRM Application 

   @ValidCredentials
   Scenario: Login with valid credentials
    
    Given User is on HRMLogin page
    When User enters username as "Admin" and password as "admin123"
    Then User should be able to login sucessfully and new page open

Step 9 – Create the Step Definition class or Glue Code for the Test Scenario

Create a Java Class for each page where define WebElements as variables using Annotation @FindBy and Create methods for actions performed on WebElements. Here, I’m going to create 2 classes – Login and Home.

Login class contains WebElements which are identified by @FindBy annotation as shown below:-

@FindBy(name = "txtUsername")
WebElement userName;

It also create methods for the action to be performed on these webelements as shown below:-

public void login(String strUserName, String strPassword) {
 
           // Fill user name
           this.setUserName(strUserName);
 
           // Fill password
           this.setPassword(strPassword);
 
           // Click Login button
           this.clickLogin();
     }
}

The initElements is a static method of PageFactory class which is used to initialize all the web elements located by @FindBy annotation.Only after the WebElements are initialized, they can be used in the methods to perform actions.

public Login(WebDriver driver) {
           this.driver = driver;
           // This initElements method will create all WebElements
           PageFactory.initElements(driver, this);
     }

Below is the sample code of Login page.

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

public class Login {

	/**
	 * 
	 * All WebElements are identified by @FindBy annotation
	 * 
	 */

	WebDriver driver;

	@FindBy(name = "txtUsername")
	WebElement userName;

	@FindBy(name = "txtPassword")
	WebElement password;

	@FindBy(id = "logInPanelHeading")
	WebElement titleText;

	@FindBy(id = "btnLogin")
	WebElement login;

	public Login(WebDriver driver) {

		this.driver = driver;

		// This initElements method will create all WebElements
		PageFactory.initElements(driver, this);
	}

	// Set user name in textbox
	public void setUserName(String strUserName) {
		userName.sendKeys(strUserName);
	}

	// Set password in password textbox
	public void setPassword(String strPassword) {
		password.sendKeys(strPassword);
	}

	// Click on login button
	public void clickLogin() {
		login.click();
	}

	// Get the title of Login Page
	public String getLoginTitle() {
		return titleText.getText();
	}

	public void login(String strUserName, String strPassword) {

		// Fill user name
		this.setUserName(strUserName);

		// Fill password
		this.setPassword(strPassword);

		// Click Login button
		this.clickLogin();

	}
}

Below is the sample code of Home page.

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

public class HomePage {

	WebDriver driver;

	@FindBy(id = "welcome")
	WebElement homePageUserName;

	public HomePage(WebDriver driver) {
		this.driver = driver;

		// This initElements method will create all WebElements
		PageFactory.initElements(driver, this);
	}

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

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

import java.util.concurrent.TimeUnit;

import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

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

public class LoginPageDefinitions {
	String driverPath = "C:\\Users\\Desktop\\Automation\\Drivers\\geckodriver-v0.24.0-win64\\geckodriver.exe";

	WebDriver driver;

	Login objLogin;

	HomePage objHomePage;

	@Before
	public void setup() {

		// Initialize the webdriver and open the browser
		System.setProperty("webdriver.gecko.driver", driverPath);
		driver = new FirefoxDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	/**
	 * 
	 * This test go to https://opensource-demo.orangehrmlive.com/ Verify login page title as LOGIN Panel Login to application Verify the home page using welcome
	 * message
	 * 
	 */

	@Given("User is on HRMLogin page")
	public void loginTest() {

		// Create Login Page object
		objLogin = new Login(driver);

		// Verify login page text
		String loginPageTitle = objLogin.getLoginTitle();
		Assert.assertTrue(loginPageTitle.contains("LOGIN Panel"));

	}

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

		// login to application
		objLogin.login(userName, passWord);

		// go the next page
		objHomePage = new HomePage(driver);
	}

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

		// Verify home page
		Assert.assertTrue(objHomePage.getHomePageText().contains("Welcome"));

	}

	@After
	public void close() {

		// Close the browser
		driver.close();
	}
}

In the above stepdefinition or glue code, @Before and @After annotations are used for Instantizing the web browser and then closing the web browser. These are JUnit annotations. We have not identified the web elements or declared the methods in this class. All these activities are done in the respective Page Classes ie Login.java and Home.java.

Step 10 – Create a JUnit Cucumber Runner class to execute the test scenarios

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)

@CucumberOptions(features = {
		"src/test/resources/features/HRMLoginPage.feature" }, glue = "com.cucumber.pageobjectmodel")
public class CucumberRunnerTest {

}

Note:- The name of Runner class should end with Test otherwise we can’t run the tests using Command Line.

Step 11 – Run the tests from JUnit

You can execute test script by right clicking on TestRunner class -> Run As JUnit.

Step 12 – Run the tests from Command Line

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

mvn test

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 Cucumber Service.

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Integration of Cucumber with Selenium and JUnit

HOME

As we know Cucumber is a BDD Tool and Selenium Webdriver is use for the automation of web application. Imagine we need to build a test framework which can be used by business to understand the test scenarios and as well can test the web application. This can be achieved by integrating Cucumber with Selenium.

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

  1. Cucumber
  2. Java 8 or above
  3. JUnit
  4. Maven
  5. Selenium

Steps to setup Cucumber Test Automation Framework with Selenium

  1. Download and Install Java on system
  2. Download and setup Eclipse IDE on system
  3. Setup Maven
  4. Create a new Maven Project
  5. Create source folder – src/test/resources to create test scenarios in Feature file
  6. Add Selenium and Cucumber dependencies to the project
  7. Add Maven Compiler Plugin
  8. Create a feature file under src/test/resources
  9. Create the Step Definition class or Glue Code
  10. Create a Cucumber Runner class
  11. Run the tests from JUnit
  12. Run the tests from Command Line
  13. Cucumber Report Generation

Step 1- Download and Install Java

Cucumber and Selenium needs 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 system

The Eclipse IDE (integrated development environment) provides strong support for Java developer. The Eclipse IDE for Java Developers distribution is designed to support standard Java development. It includes support for the Maven and Gradle build system and support for the Git version control system. 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 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 which is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

Step 4 – 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.cucumber
Artifact Id – seleniumdemo
Version – 0.0.1-SNAPSHOT
Package – com.cucumber.seleniumdemo

Maven Dependency (pom.xml) looks like something shown below for a new Maven project.

Step 5 – Create source folder src/test/resources to create test scenarios in Feature file

When a new Maven Project is created, it has 2 folders – src/main/java and src/test/java. To create test scenarios, we need a new source folder called – src/test/resources. To create this folder, right click on your maven project ->select New ->Java and then Source Folder.

Mention the source folder name as src/test/resources and click Next button. This will create a source folder under your new Maven project as shown in the below image.

Step 6 – Add Selenium and Cucumber dependencies to the project

Add below mentioned Selenium and Cucumber dependencies to the project.

 <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>6.8.1</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>6.8.1</version>
      <scope>test</scope>
     </dependency>

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>

Step 7 – Add Maven Compiler Plugin

The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:

  • compile – compile main source files
  • testCompile – compile test source files
<build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
       </plugins>
   </build>

The complete pom.xml will look like below image

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.cucumber</groupId>
  <artifactId>seleniumdemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>seleniumdemo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>6.8.1</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>6.8.1</version>
      <scope>test</scope>
     </dependency>

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>
    
    
  </dependencies>
  
   <build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
       </plugins>
   </build>
</project>

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

Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. In this feature file, I have created a scenario for successful login and another one for failed login. The test scnerios are written in Gherkins language

Feature: Login to HRM Application 

   @ValidCredentials
   Scenario: Login with valid credentials
    
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login sucessfully
    
   @InValidCredentials
   Scenario: Login with invalid credentials
    
    Given User is on Home page
    When User enters username as "username"
    And User enters password as "password"
    Then Login will be unsuccessfull with error message "Invalid credentials"

Step 9 – Create the stepdefinition class corresponding to the feature file to test the scenarios

public class LoginPagedefinition {

	WebDriver driver;

	@Given("User is on Home page")
	public void userOnHomePage() {
		System.setProperty("webdriver.chrome.driver",
				"C:\\Users\\Vibha\\Desktop\\SeleniumKT\\chromedriver_win32\\chromedriver.exe");
		driver = new ChromeDriver();
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	@When("User enters username as {string}")
	public void entersUsername(String userName) throws InterruptedException {

		System.out.println("Username Entered");
		driver.findElement(By.name("txtUsername")).sendKeys(userName);

	}

	@When("User enters password as {string}")
	public void entersPassword(String passWord) throws InterruptedException {

		System.out.println("Password Entered");
		driver.findElement(By.name("txtPassword")).sendKeys(passWord);

		driver.findElement(By.id("btnLogin")).submit();
	}

	@Then("User should be able to login sucessfully")
	public void sucessfullLogin() throws InterruptedException {

		String newPageText = driver.findElement(By.id("welcome")).getText();
		System.out.println("newPageText :" + newPageText);
		assertThat(newPageText, containsString("Welcome"));

	}

	@Then("Login will be unsuccessfull with error message {string}")
	public void unsucessfullLogin(String errorMessage) throws InterruptedException {

		String actualErrorMessage = driver.findElement(By.id("spanMessage")).getText();
		System.out.println("Actual Error Message :" + actualErrorMessage);

		assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));

	}
}

Step 10 – Create a Cucumber Runner class to execute the test scenarios

We need to create a class called Runner class to run the tests. This class will use the JUnit annotation @RunWith(), which tells JUnit what is the test runner class.

package com.cucumber.seleniumdemo.runner;

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)
@CucumberOptions(features = {
		"src/test/resources/features/LoginPage.feature" }, glue = "com.cucumber.seleniumdemo.definition")

public class CucumberRunnerTest {

}

Step 11 – Test Execution through JUnit

Go to Runner class and right click Run As Junit. The tests will run as JUnit tests.

Step 12 – Run the tests from Command Line

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

mvn test

The execution screen looks like something as shown below

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

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Run Cucumber Test from Maven Command Line

HOME

To have a successful and effective implementation of a test framework, it is always advisable that the test framework supports test execution in multiple ways.
The 2 most commonly used ways to executes tests in Cucumber Framework is by running the tests using JUnit and Maven.

To execute tests using JUnit, we need to create a JUnit TestRunner. Whereas we need a Maven project to execute Cucumber tests from Command Line.

Create a Maven project and add the below mention dependencies in your Maven project.

  <dependencies>
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
 
 <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>6.8.1</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-junit</artifactId>
      <version>6.8.1</version>
      <scope>test</scope>
     </dependency>

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>3.141.59</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.10.0</version>
      <scope>test</scope>
     </dependency>

 </dependencies>
 
  <build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.7.0</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>
            <encoding>UTF-8</encoding>          
         </configuration>
       </plugin>                
       </plugins>
   </build>
   
</project>

Run Test from Command Line

1. Open the command prompt and change directory to the project location where pom.xml is present.

cd C:\Users\Vibha\eclipse-workspace-test\demo

2. All feature files should be in src/test/resources and create Cucumber Runner class as CucumberRunnerTest.
Note:- The Runner class name should end with Test to execute the tests from Command Line
Run the following command in the command prompt:

mvn test

mvn test runs Cucumber Features using Cucumber’s JUnit Runner. The @RunWith (Cucumber.class) annotation on the TestRunner class tells JUnit to start Cucumber. Cucumber run time parses the command-line options to know what Feature to run, where the Glue Code lives, what plugins to use, and so on.

3. Below screenshot shows that CucumberRunnerTest class is triggered.

4. Below screenshot shows that build success output.

Overriding Cucumber Options

Cucumber provides several options that can be passed to on the command-line.

1. Running Scenarios using Tags from Command Line

If you are using Maven and want to run a subset of scenarios tagged with @ValidCredentials.

mvn test -Dcucumber.filter.tags="@ValidCredentials"

There is one more way to execute Cucumber tests with tags

mvn test -Dcucumber.options="--tags @ValidCredentials"

2. Running a Feature file from Command Line

Suppose you want to run single Feature File from the command line, then use the below syntax

mvn test -Dcucumber.options="src/test/resources/features/CucumberTagsExample.feature"

3. Creating Cucumber Report from Command Line

If we want to generate a different report, then we can use the following command and see the JUnit report generate at the location mentioned:

mvn test -Dcucumber.options="--plugin junit:target/cucumber-reports/cucumberReport.xml

4. Passing multiple Parameter from Command Line

If we want to pass more than one parameters, then we can use the following command

mvn test -Dcucumber.options="src/test/resources/features/CucumberTagsExample.feature" -Dcucumber.filter.tags="@InValidCredentials"

5. Running a Scenario without tag from Command Line

If we want to run single Scenario from the command line and no tag is assigned to that scenario, this is how we specify

 mvn test -Dcucumber.options="src/test/resources/features/CucumberTagsExample.feature:12"

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

In the next tutorial, I have explained to run Cucumber Gradle tests from Command Line.