DataTables in Cucumber

Last Updated On

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.

Table Of Contents

  1. Prerequisite
  2. Project Structure
    1. Table into List of a List of Strings
    2. Table into List of Maps
    3. Table into Single Map
    4. Table into map that uses a list as its value
  3. Cucumber Data Tables Example in Java
    1. Data Table without Header Example
    2. Data Table with Header and Single Row Example
    3. Data Table with Header and Multiple Rows Example

Prerequisite

  1. Cucumber – 7.15.0
  2. Java – 17
  3. Selenium – 4.16.1
  4. JUnit – 4.13.2 ( You can use TestNG also)
  5. Cucumber JUnit – 7.15.0 (If using TestNG, then replace this with Cucumber TestNG)

Project Structure

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 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 - Data Table without Header

    Given User is on HRMLogin page
    When User enters valid credentials
      | Admin | admin123 |
    Then User should be able to login successfully and new page open

Below is the Step Definition of the above scenario.

import io.cucumber.datatable.DataTable;
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;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;

public class DataTableDefinitions {

    WebDriver driver;

 @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

    @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<List<String>> signUpForm = dataTable.asLists(String.class);
        String userName = signUpForm.get(0).get(0);
        String passWord = signUpForm.get(0).get(1);
        driver.findElement(By.name("username")).sendKeys(userName);
        driver.findElement(By.name("password")).sendKeys(passWord);
        driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();
    }

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

        String newPageText = driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();
        System.out.println("newPageText :" + newPageText);
        assertThat(newPageText, containsString("Dashboard"));
    }

    @After
    public void teardown(){
        driver.quit();
    }
}


To run the Feature file, we need a Cucumber TestRunner.

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(monochrome = true, plugin = "pretty", features = "src/test/resources/Features/DataTable.feature",
        glue = "definitions", tags="@ValidCredentials")

public class CucumberRunnerTest {
}

The output of the above program is

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

Cucumber converts the above table into a list of lists. It treats 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 invalid credential - Header with Single Row

    Given User is on HRMLogin page
    Then User enters invalid credentials and Login will be unsuccessful with error message
      | Username  | Password   | ErrorMessage        |
      | Admin1    | admin123!$ | Invalid credentials |

Below is the Step Definition of the above scenario.

package org.example.definitions;

import io.cucumber.datatable.DataTable;
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;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;
import java.util.List;
import java.util.Map;

public class DataTableDefinitions {

    WebDriver driver;

    @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

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

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

    @Then("User enters invalid credentials and Login will be unsuccessful with error message")
    public void entersInvalidCredential(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);
        driver.findElement(By.name("username")).sendKeys(userName);

        String passWord = user.get(0).get("Password");
        System.out.println("Password :" + passWord);
        driver.findElement(By.name("password")).sendKeys(passWord);

        driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();

        String errorMessage = user.get(0).get("ErrorMessage");
        String actualErrorMessage = driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
        System.out.println("Actual Error Message :" + actualErrorMessage);
        Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));

    }

    @After
    public void teardown(){
        driver.quit();
    }

}

The output of the above program is

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 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 table example with multiple rows of data with the header. This is helpful when we want to test multiple combinations of data in a step.

  @Multiple_InValidCredentials
  Scenario: Login with invalid credentials - Data Table with Header and Multiple Rows

    Given User is on HRMLogin page
    Then User enters invalid credentials and Login will be unsuccessful with custom error messages
      | Username    | Password  | ErrorMessage         |
      | Admin1      | admin123! | Invalid credentials  |
      | Admina      | admin123a | Invalid credentials  |
   

Below is the Step Definition of the above scenario

import io.cucumber.datatable.DataTable;
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;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;

public class DataTableDefinitions {

    WebDriver driver;

     @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

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

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

     @Then("User enters invalid credentials and Login will be unsuccessful with custom error messages")
    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("username")).sendKeys(userName);

            String passWord = form.get("Password");
            System.out.println("Password :" + passWord);
            driver.findElement(By.name("password")).sendKeys(passWord);

            driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();

            String errorMessage = form.get("ErrorMessage");
            String actualErrorMessage = driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
            System.out.println("Actual Error Message :" + actualErrorMessage);

            Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));

        }
    }

    @After
    public void teardown(){
        driver.quit();
    }

}

The output of the above program is

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

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

ArrayList in Java

HOME

  1. What is the difference between Array and ArrayList?
  2. How to create an ArrayList?
  3. How to add elements to an ArrayList?
  4. How to remove elements from ArrayList?
  5. ArrayList SizeMethod
  6. Method to iterate through ArrayList

import java.util.ArrayList; // import the ArrayList class
ArrayListCompanies = new ArrayList(); // Create an ArrayList object


1) To add the element at the end of the List. 

Companies.add("Samsung");

2) To add the element at the specified location in ArrayList, we can specify the index in the add method like this.

Companies.add(2,"Microsoft");

4) How to remove elements from ArrayList?


1) To remove the element with name. 

Companies.remove("MI");

2) To remove the element at the specified location in ArrayList, we can specify the index in the remove method. 

Companies.remove(1);

5) ArrayList SizeMethod

To find out how many elements an ArrayList have, use the size() method. 

Companies.size();

Let me show how to add and remove elements from an ArrayList with the help of an example.

package com.example.definitions;

import java.util.ArrayList;
import java.util.function.Predicate;

public class ArrayList_IteratorExample {

    public static void main(String[] args) {

        //Create ArrayList of String
        ArrayList<String> Companies = new ArrayList();

        // Check if an ArrayList is empty
        System.out.println("Is Company List empty :"+Companies.isEmpty());

        // Adding new elements to the ArrayList
        Companies.add("Samsung");
        Companies.add("Apple");
        Companies.add("Motorola");
        Companies.add("Google");
        Companies.add("Sony");
        Companies.add("Blackberry");
        System.out.println("Company List is :"+Companies);

        // Adding an element at a particular index in an ArrayList
        Companies.add(2,"Microsoft");
        System.out.println("Updated Company List is:"+Companies);

        // Find the size of an ArrayList
        System.out.println("Size of Company List: "+Companies.size());

        // Retrieve the element at a given index
        System.out.println("First Company in list: "+Companies.get(0));

        // Retrieve the last element from ArrayList
        String LastCompany = Companies.get(Companies.size()-1);
        System.out.println("Last Company in list: "+LastCompany);

        // Remove the element
        Companies.remove("MI");

        // Remove the element at index '1'
        Companies.remove(1);
        System.out.println("Updated Company List after removal is:"+Companies);

        // Remove first occurrence of the given element from the ArrayList
        // (The remove() method returns false if the element does not exist in the ArrayList)
        boolean isRemoved = Companies.remove("Lenovo");
        System.out.println("Lenovo exists in Company List :"+isRemoved);

        // Remove all the elements that satisfy the given predicate
        Predicate<String> newCompanies = company -> company.startsWith("B");
        Companies.removeIf(newCompanies);

        System.out.println("After Removing all elements that start with \"B\": " + Companies);
    }
}

6) Method to iterate through ArrayList

There are various methods to iterate through ArrayList. We will discuss few of the methods.
1) Iterator interface
2) For -each loop
3) For loop
4) While loop

package com.example.definitions;

import java.util.ArrayList;

public class ArrayList_IteratorExample {

    public static void main(String[] args) {

        //Creating arraylist
        ArrayList<String> Companies = new ArrayList();

        // Adding new elements to the ArrayList
        Companies.add("Samsung");
        Companies.add("Apple");
        Companies.add("Motorola");
        Companies.add("Google");
        Companies.add("Sony");
        Companies.add("Blackberry");

        //Traversing list through Iterator
        for(String a:Companies)
            System.out.println(a);
        System.out.println("------------------------------------------");

        //Traversing list through for loop
        for(int i=0;i<Companies.size();i++)
        {
            System.out.println(Companies.get(i));
        }
        System.out.println("------------------------------------------");

        // Traversing list through For-Each loop
        for(String a:Companies)
            System.out.println(a);
    }
}

How to add header to Python Requests

HOME

Headers = { “Authorization” : ”our_unique_secret_token” }

pip install -U requests

pip install -U pytest

import requests

ENDPOINT = 'https://reqres.in/api/users'


def test_add_header():
    request_body = {
        "name": "Vibha",
        "Job": "CEO"
    }

    header = {"Content-Type":  "application/json; charset=utf-8"}

    response = requests.post(ENDPOINT, request_body, header)
    print(response.json())
    print("Request Header", response.request.headers)
    print("Response Header", response.headers)
    assert response.status_code == 201
    assert response.headers["Content-Type"] == "application/json; charset=utf-8"

assert response.headers["Content-Type"] == "application/json; charset=utf-8"

pytest PostRequest_test.py -s

Integration of Cucumber with Selenium and JUnit4

HOME

As we know, Cucumber is a BDD Tool and Selenium Webdriver is used for the automation of web applications. Imagine we need to build a test framework that can be used by businesses 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.

Table of Contents

Dependency List:

  1. Cucumber – 7.14.0
  2. Java 17
  3. JUnit – 4.13.2
  4. Maven – 3.9.5
  5. Selenium – 4.15.0

Implementation Steps

The above steps are explained in detail.

Step 1- Download and Install Java

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

Step 2 – Download and setup Eclipse IDE on the system

The Eclipse IDE (integrated development environment) provides strong support for Java developers. 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 a very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool that is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

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

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

Step 5 – Create a new Maven Project

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

Group Id – org.example
Artifact Id – Cucumber_JUnit4_Demo
Version – 0.0.1-SNAPSHOT
Package – cucumber

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

Step 6 – Create source folder src/test/resources

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. The Feature file is created in the src/test/resources 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 7 – Add Selenium and Cucumber dependencies to the project

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

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.14.0</cucumber.version>
    <selenium.version>4.15.0</selenium.version>
    <junit.version>4.13.2</junit.version>
    <maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>

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

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

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

Step 8 – 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>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
      </plugin>
    </plugins>
  </build>
</project>

The complete pom.xml will look like the 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>org.example</groupId>
  <artifactId>Cucumber_JUnit4_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.14.0</cucumber.version>
    <selenium.version>4.15.0</selenium.version>
    <junit.version>4.13.2</junit.version>
    <maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>

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

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

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

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
      </plugin>
    </plugins>
  </build>
</project>

Step 9 – Create a feature file (LoginPage.feature)

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 a failed login. The test scenarios are written in the Gherkins language. A feature file contains all the test scenarios and is placed in src/test/resources/features.

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 10 – Create the step definition class

The StepDefinition class is created in src/test/java. The StepDefinition class contains the test code corresponding to the steps of Test Scenario in the Feature File.

It is recommended to create a package with a name such as org.example.cucumber.stepdefinitions in src/test/java and create the step definition java file corresponding to the feature files in that package

package org.example.definitions;

import java.time.Duration;

import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

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

	WebDriver driver;
	
	@Before
    public void setUp() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }
	 
    @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)  {
 
        System.out.println("Username Entered");
        driver.findElement(By.name("username")).sendKeys(userName);
       
 
    }
 
    @When("User enters password as {string}")
    public void entersPassword(String passWord)  {
 
        System.out.println("Password Entered");
        driver.findElement(By.name("password")).sendKeys(passWord);
        driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();
    }
 
    @Then("User should be able to login sucessfully")
    public void sucessfullLogin()  {
 
    	 String homePageHeading = driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();

         //Verify new page - HomePage
         Assert.assertEquals("Dashboard",homePageHeading);   
 
    }
 
    @Then("Login will be unsuccessfull with error message {string}")
    public void unsucessfullLogin(String expectedErrorMessage)  {
 
    	 String actualErrorMessage = driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();

         // Verify Error Message
         Assert.assertEquals( expectedErrorMessage, actualErrorMessage);
 
    }
    
    @After
    public void teardown() {

        driver.quit();
    }
  
}

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

It is recommended to create a package with a name such as org.example.cucumber.runner in src/test/java and create the CucumberRunnerTest (Runner) java file corresponding to that package.

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 org.example.cucumber.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 = "org.example.cucumber.definitions")
 
public class CucumberRunnerTest {

}

Step 12 – Test Execution through JUnit

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

Step 13 – 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 clean test

Step 14 – Cucumber Report Generation

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

cucumber.publish.enabled=true

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

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

Java Tutorials

Java is a general-purpose programming language that is a concurrent, class-based, and object-oriented language. Java follows the concept of “write once and run anywhere (WORA).” This means that compiled Java code can be run on all different platforms that support Java. There’s no need for recompilation.

Eclipse IDE

Chapter 1 How to Download and Install Eclipse IDE
Chapter 2 How to Clone a project from GitLab using Eclipse
Chapter 3 How to Export Eclipse projects to GitLab

IntelliJ IDE

Chapter 1 How to install IntelliJ on Windows
Chapter 2 How to create a Java project in IntelliJ
Chapter 3 How to Clone a project from GitLab using IntelliJ
Chapter 4 How to Export IntelliJ project to GitLab

Basics of Java

Chapter 1 How to Download & Install Java JDK 11 in Windows
Chapter 2 Data Types and Operators in Java
Chapter 3 Decision Making in Java – If, If Else, Switch, Break, Continue
Chapter 4 Loop Control Statements in Java – For, While, Do While, Enhanched For Loop
Chapter 5 String Manipulation
Chapter 6 Difference between == and equals() method in Java
Chapter 7 Arrays in Java
Chapter 8 Java Access Modifiers: Explained with Examples
Chapter 9 ArrayList in Java
Chapter 10 How to compare ArrayLists – contains?
Chapter 11 How to compare ArrayLists – containsAll method?
Chapter 12 Methods in Java
Chapter 13 Method Overloading in Java
Chapter 14 Constructors in Java   
Chapter 15 This Keyword in Java   
Chapter 16 Static Keyword – Static Variable and Static Method in Java
Chapter 17 Difference between Static Method and Non-Static Method
Chapter 18 How to use Java Lambda expression to create thread via Runnable function
Chapter 19 runAsync and supplyAsync in ComputableFuture in Java8
Chapter 20 HashMap in Java
Chapter 21 LinkedHashMap in Java
Chapter 22 Iterators in Java

OOPs Concepts

Chapter 1 Class and Object in Java
Chapter 2 Inheritance in Java
Chapter 3 Encapsulation in Java
Chapter 4 Polymorphism in Java
Chapter 5 Abstraction in Java
Chapter 6 Interface in Java
Chapter 7 Difference between Abstract Class and Interface

Exceptions in Java

Chapter 1 Exception Handling in Java
Chapter 2 Java Exceptions Tutorial: Built-in and User-defined Exceptions
Chapter 3 Flow control in try catch finally in Java
Chapter 4 Multiple Catch Exceptions
Chapter 5 Throw in Java
Chapter 6 Throws in Java

Data Handling (Excel Manipulation)

Chapter 1 How to download and install Apache POI
Chapter 2 Reading Excel Data with Apache POI in Java
Chapter 3 How to Write Data to Excel File in Java using Apache POI
Chapter 4 How to update existing excel in Java
Chapter 5 Java Excel Tutorial: Creating Excel with Formulas Using Apache POI
Chapter 6 Change Font Style in Excel with Apache POI – NEW

Multiple Choice Questions

Chapter 1 Multiple questions on Exception Handling in Java

Java Library

Chapter 1 AssertJ – Fluent Assertions in Java

Conditional Hooks in Cucumber

HOME

In the previous tutorial, I 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 prerequisites 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 the 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 the above feature file.

import io.cucumber.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 separate class.

import io.cucumber.java.After;
import io.cucumber.java.AfterStep;
import io.cucumber.java.Before;
import io.cucumber.java.BeforeStep;

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.

import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

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

public class MyRunnerTests {

}

The output of the above execution is

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

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

How to test PATCH Request Using Python Requests

HOME

pip install -U requests

pip install -U pytest

import requests

ENDPOINT = 'https://reqres.in/api/users/2'


def test_partiallyupdate_user():
    request_body = {
        "Job": "CFO"
    }

    response = requests.patch(ENDPOINT, request_body)
    print(response.text)
    assert response.status_code == 200
    response_body = response.json()
    assert response_body["Job"] == "CFO"

Allure Reports

HOME

Allure Framework is a lightweight, flexible multi-language test report tool that not only displays a very concise representation of what has been tested in a neat web report form, but also allows everyone involved in the development process to extract the most useful information from everyday test execution.

Allure Report for Maven Projects

Chapter 1 What is Allure Report?
Chapter 2 Integration of Allure Report with Selenium and JUnit4
Chapter 3 Integration of Allure Report with Selenium and JUnit5
Chapter 4 Integration of Allure Report with Selenium and TestNG
Chapter 5 Allure Report with Cucumber, Selenium and JUnit4
Chapter 6 Allure Report with Cucumber, Selenium and TestNG
Chapter 7 Integration of Allure Report with Rest Assured and JUnit4
Chapter 8 Integration of Allure Report with Rest Assured and TestNG
Chapter 9 Allure Report for Cucumber7, Selenium, and JUnit5
Chapter 10 Integration of Allure Report with Jenkins

Allure Report for Gradle Projects

Chapter 1 Gradle – Allure Report for Selenium and TestNG
Chapter 2 Gradle – Allure Report for Selenium and JUnit4
Chapter 3 Gradle – Allure Report for Cucumber, Selenium and TestNG

Difference between JUnit4 and JUnit5

HOME

In this article, we’ll see an overview of the differences between the two versions of the library.

1. Architecture

JUnit 4 has everything bundled into a single jar file whereas JUnit 5 is composed of 3 sub-projects i.e. JUnit Platform, JUnit Jupiter, and JUnit Vintage.

JUnit4

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

JUnit Platform: It defines the TestEngine API for developing new testing frameworks that run on the platform.
JUnit Jupiter: It has all new JUnit annotations and TestEngine implementation to run tests written with these annotations.
JUnit Vintage: To support running JUnit 3 and JUnit 4 written tests on the JUnit 5 platform.

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>

2. JDK Version

JUnit 4 requires Java 5 (or higher) whereas JUnit 5 requires Java 8 (or higher).

3. Imports

JUnit 5 uses the org.JUnit package for its annotations and classes whereas JUnit 5 uses the new org.JUnit.jupiter package for its annotations and classes. For example, org.JUnit.Test becomes org.JUnit.jupiter.api.Test.
@Before annotation of JUnit4 is renamed to @BeforeEach in JUnit5
@After annotation of JUnit4 is renamed to @AfterEach in JUnit5
@BeforeClass annotation of JUnit4 is renamed to @BeforeAll in JUnit5
@AfterClass annotation of JUnit4 is renamed to @AfterAll in JUnit5

4. Assertions

JUnit 5 assertions are now in org.JUnit.jupiter.api.Assertions whereas JUnit4 assertions are in org.JUnit.Assert. Most of the common assertions, like assertEquals() and assertNotNull() look the same as before, but there are a few key differences:

  • The error message is now the last argument, for example, assertEquals(“my message”, 1, 2) would be assertEquals(1, 2, “my message”)
  • Most assertions now accept a lambda that constructs the error message, which is only called when the assertion fails.
    @Test
    void nullNegative() {
        String str = "Summer";

        Assertions.assertNull(str, () -> "The string should be null");
    }

The output of the above program is

  • assertTimeout() and assertTimeoutPreemptively() have replaced the @Timeout annotation (note that there is a @Timeout annotation in JUnit 5, but it works differently than JUnit 4).
  • There are several new assertions in JUnit5- assertAll(), assertIterableEquals(), assertLinesMatch(), assertThrows() and assertDoesNotThrow(). To know more about assertions in JUnit5, please refer to this tutorial – JUnit5 Assertions Example

5. Assumptions

In Junit 4, org.junit.Assume contains methods for stating assumptions about the conditions in which a test is meaningful. It has the following five methods:

  • assumeFalse()
  • assumeNoException()
  • assumeNotNull()
  • assumeThat()
  • assumeTrue()

JUnit5 has the following three methods:

  • assumeFalse()
  • assumingThat​()
  • assumeTrue()

Below is an example of assumeThat() annotation in JUnit5.

    @Test
    void assumingThatTest() {
        System.setProperty("ENV", "UAT");
        assumingThat(
                "UAT".equals(System.getProperty("ENV")),
                () -> {
                    // Since the condition is true, this assertion will get executed
                    System.out.println("Assuming that executable executed");
                    assertEquals((num1+num2),num4,"The product of "+ num1 +" and "+ num2 +" is not equal to "+num4);
                });
        
        System.out.println("Loop outside");
        assertEquals((num5-num2),num6,"The difference of "+ num5 +" and "+num2+" is not equal to " + num6);
    }

The output of the above program is

6. Conditional Test Execution

In JUnit4, @Ignore is used to skip the execution of a test whereas @Disabled or one of the other built-in execution conditions is used to skip the execution of the test in JUnit5. To know more about skipping the tests in JUnit5, please refer to this tutorial – How to disable tests in JUnit5 – @Disabled.

Below is an example of @Disabled in JUnit5.

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.junit.jupiter.api.Assertions.*;
 
class DisabledTestsDemo {
 
    WebDriver driver;
 
    @BeforeEach
    public void setUp() {
         
        WebDriverManager.chromedriver().setup();
        ChromeOptions chromeOptions = new ChromeOptions();
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().fullscreen();
        driver.get("http://automationpractice.com/index.php");
 
    }
 
    @Disabled("This test is not applicable for Sprint 14")
    @Test
    void verifyPopularLink() {
 
        boolean displayed = driver.findElement(By.xpath("//*[@id='home-page-tabs']/li[1]/a")).isDisplayed();
        assertTrue(displayed);
    }
 
    @Test
    void verifyContactNumber() {
 
        String contactDetail = driver.findElement(By.xpath("//span[@class='shop-phone']/strong")).getText();
        assertEquals("0123-456-789", contactDetail);
    }
 
    @Disabled("This test is blocked till bug 1290 is fixed")
    @Test
    void verifyWomenLink() {
 
        boolean enabled = driver.findElement(By.xpath("//*[@id='block_top_menu']/ul/li[1]/a")).isEnabled();
        assertTrue(enabled);
    }
 
    @AfterEach
    public void tearDown() {
        driver.close();
    }
}

The output of the above program is

JUnit 5 provides the ExecutionCondition extension API to enable or disable a test or container (test class) conditionally. This is like using @Disabled on a test but it can define custom conditions. There are multiple built-in conditions, such as:

  • @EnabledOnOs and @DisabledOnOs: Enables a test only on specified operating systems.
  • @EnabledOnJre and @DisabledOnJre: Specifies the test should be enabled or disabled for specific versions of Java.
  • @EnabledIfSystemProperty: Enables a test based on the value of a JVM system property.
  • @EnabledIf: Uses scripted logic to enable a test if scripted conditions are met.

7. Extending JUnit

@RunWith no longer exists; superseded by @ExtendWith in JUnit5.

In JUnit 4, customizing the framework generally meant using a @RunWith annotation to specify a custom runner. Using multiple runners was problematic, and usually required chaining or using a @Rule. This has been simplified and improved in JUnit 5 using extensions.

import net.serenitybdd.core.Serenity;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import net.thucydides.core.annotations.Managed;
import net.thucydides.core.annotations.Steps;
import net.thucydides.core.annotations.Title;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.WebDriver;
import static org.assertj.core.api.Assertions.assertThat;
 
 @ExtendWith(SerenityJUnit5Extension.class)
 class ApplicationLoginJUnit5Tests {
 
        @Managed
        WebDriver driver;
 
        @Steps
        NavigateAction navigateAction;
 
        @Steps
        StepLoginPage loginPage;
 
        @Test
        @Title("Login to application with valid credentials navigates to DashBoard page")
 
         void successfulLogin() {
 
            navigateAction.toTheHomePage();
 
            // When
            loginPage.inputUserName("Admin");
            loginPage.inputPassword("admin123");
            loginPage.clickLogin();
 
            // Then
            Serenity.reportThat("Passing valid credentials navigates to DashBoard page",
                    () -> assertThat(dashboardPage.getHeading()).isEqualToIgnoringCase("DashBoard"));
        }
    }

8. Non-public Test Methods are Allowed

JUnit 5 test classes and test methods are not required to be public. We can now make them package protected.
JUnit internally uses reflection to find test classes and test methods. Reflection can discover them even if they have limited visibility, so there is no need for them to be public.

9. Repeat Tests

JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with @RepeatedTest and specifying the total number of repetitions desired. To know more about RepestedTest, please refer to this tutorial – How to Retry Test in JUnit5 – @RepeatedTest

Below is the example of @RepeatedTest in JUnit5.

    @RepeatedTest(3)
    void repeatedTestWithRepetitionInfo1(RepetitionInfo repetitionInfo) {
        assertEquals(3, repetitionInfo.getTotalRepetitions());
    }

The output of the above program is

10. Parameterized Tests

Test parameterization existed in JUnit 4 with built-in libraries like JUnit4Parameterized or third-party libraries like JUnitParams. In JUnit 5, parameterized tests are completely built-in and adopt some of the best features from JUnit4Parameterized and JUnitParams. To know more about the parameterized tests in JUnit5, please refer to this tutorial – How to parameterized Tests in JUnit5.

Below is an example of parameterized Test in JUnit5.

public class CSVParameterizedTest {

    @ParameterizedTest
    @CsvSource({
            "java,      4",
            "javascript,   7",
            "python,    6",
            "HTML,    4",
    })


    void test(String str, int length) {
        assertEquals(length, str.length());
    }
}

The output of the above program is

Congratulations. We have gone through the differences between JUnit4 and JUnit5. Happy Learning!!

How to test DELETE Request Using Python Requests

HOME

pip install -U requests

pip install -U pytest

import requests

ENDPOINT = 'https://reqres.in/api/users/2'


def test_delete_user():

    response = requests.delete(ENDPOINT)
    assert response.status_code == 204