Deserialization – How to convert XML to Java Objects using Jackson API

HOME

The previous tutorials have explained the conversion of Java Objects to XML using Jackson API. This tutorial explains parsing the XML document to Java objects using Jackson API.

To parse the XML, we will use the Jackson library. Use the latest Jackson library.

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.16.0</version>
</dependency>

Jackson allows us to read the contents of an XML file and deserialize the XML back into a Java object. In our example, we will read an XML document containing details about an Employee, and use Jackson to extract this data and use it to create Java objects containing the same information.

First, let us create an XML document matching our class to read from.

Create deserialize.xml with the following contents:

<Employee>
  <firstName>Vibha</firstName>
  <lastName>Singh</lastName>
  <age>35</age>
  <salary>135000.0</salary>
  <designation>Manager</designation>
  <contactNumber>+919999988822</contactNumber>
  <emailId>abc@test.com</emailId>
  <gender>female</gender>
  <maritalStatus>married</maritalStatus>
</Employee>

Deserialization – It is the reverse of serializing. In this process, we will read the Serialized byte stream from the file and convert it back into the Class instance representation. Here, we are converting a XML to an Employee class object.

Let us add a deserializeFromXML() function to deserialize the XML file above into a Java object:

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.example.simple.Employee;
import org.junit.Test;

import java.io.File;
import java.io.IOException;

public class DeserializeXMLTest {
    @Test
    public void deserializeFromXML() {

        XmlMapper xmlMapper = new XmlMapper();
        String userDir = System.getProperty("user.dir");

        // Converting Employee XML to Employee class object
        try {
            Employee emp = xmlMapper.readValue(new File(userDir + "\\src\\test\\resources\\XMLExample.xml"),
                    Employee.class);

            System.out.println("Deserialized data: ");
            System.out.println("First Name of employee : " + emp.getFirstName());
            System.out.println("Last Name of employee : " + emp.getLastName());
            System.out.println("Age of employee : " + emp.getAge());
            System.out.println("Salary of employee : " + emp.getSalary());
            System.out.println("Designation of employee : " + emp.getDesignation());
            System.out.println("Contact Number of employee : " + emp.getContactNumber());
            System.out.println("EmailId of employee : " + emp.getEmailId());
            System.out.println("Marital Status of employee : " + emp.getMaritalStatus());
            System.out.println("Gender of employee : " + emp.getGender());

        } catch (StreamReadException e) {
            e.printStackTrace();
        } catch (DatabindException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The output of the above program is shown below:

Manipulating Nested Elements in XML

Let us enhance our XML file to add nested elements and loops, and modify our code to deserialize the following updated structure.

<Employees>
  <name>
    <firtsname>John</firtsname>
    <middlename>Dave</middlename>
    <lastname>William</lastname>
  </name>
  <contactdetails>
    <deskNumber>00-428507</deskNumber>
    <mobileNumber>+917823561231</mobileNumber>
    <emergencyDetails>
      <emergency_no1>+91 1212898920</emergency_no1>
      <emergency_no2>+91 9997722123</emergency_no2>
      <emergency_no3>+91 8023881245</emergency_no3>
    </emergencyDetails>
  </contactdetails>
  <age>30</age>
  <salary>75000.0</salary>
  <designation>Manager</designation>
  <emailId>abc@test.com</emailId>
  <gender>female</gender>
  <maritalStatus>married</maritalStatus>
</Employees>

There will be a slight change in the deserializeFromXML() method for the nested XML Structure.

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.example.complex.Employees;
import org.example.simple.Employee;
import org.junit.Test;
import java.io.File;
import java.io.IOException;

public class DeserializeComplexXMLTest {
    @Test
    public void deserializeFromXML() {

        XmlMapper xmlMapper = new XmlMapper();

        String userDir = System.getProperty("user.dir");

        // Converting Employee XML to Employee class object
        try {
            Employees employee2 = xmlMapper
                    .readValue(new File(userDir + "\\src\\test\\resources\\NestedXMLExample.xml"), Employees.class);
            System.out.println("Deserialized data: ");
            System.out.println("First Name of employee : " + employee2.getName().getFirtsname());
            System.out.println("Middle Name of employee : " + employee2.getName().getMiddlename());
            System.out.println("Last Name of employee : " + employee2.getName().getLastname());
            System.out.println("Age of employee : " + employee2.getAge());
            System.out.println("Salary of employee : " + employee2.getSalary());
            System.out.println("Designation of employee : " + employee2.getDesignation());
            System.out.println("Desk Number of employee : " + employee2.getContactdetails().getDeskNumber());
            System.out.println("Mobile Number of employee : " + employee2.getContactdetails().getMobileNumber());
            System.out.println("Emergency Number1 of employee : "
                    + employee2.getContactdetails().getEmergencyDetails().getEmergency_no1());
            System.out.println("Emergency Number2 of employee : "
                    + employee2.getContactdetails().getEmergencyDetails().getEmergency_no2());
            System.out.println("Emergency Number3 of employee : "
                    + employee2.getContactdetails().getEmergencyDetails().getEmergency_no3());
            System.out.println("EmailId of employee : " + employee2.getEmailId());
            System.out.println("Gender of employee : " + employee2.getGender());
            System.out.println("Marital Status of employee : " + employee2.getMaritalStatus());

        } catch (StreamReadException e) {
            e.printStackTrace();
        } catch (DatabindException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The output of the above program is shown below:

Here, you can see that when we need to serialize the nested attributes like Firstname, we have called the first Name class and then getFirstName().

System.out.println("First Name of employee : " + employee2.getName().getFirtsname());

To know about Serialization – Conversion of Java Objects to XML, you can refer to this tutorial – Serialization – How to convert Java Objects to XML using Jackson API.

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

How to split log files daily in Log4j 2?

HOME

 <RollingFile name="LogToRollingFile" fileName="logs/application.log"
                     filePattern="logs/%d{YYYY-MM}/application.%d{dd-MMM}-%i.log.gz">

 <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
</Policies>

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

  <groupId>com.example</groupId>
  <artifactId>Log4j2_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <selenium.version>4.15.0</selenium.version>
    <testng.version>7.8.0</testng.version>
    <log4j.version>3.0.0-alpha1</log4j.version>
    <maven.compiler.version>3.11.0</maven.compiler.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.surefire.failsafe.version>3.1.2</maven.surefire.failsafe.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>

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


    <!-- Log4j Dependency -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>${log4j.version}</version>
    </dependency>

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

  </dependencies>

  <build>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.failsafe.version}</version>
        <configuration>
          <skipTests>false</skipTests>
          <skip>false</skip>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>

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

  </build>

</project>

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <RollingFile name="LogToRollingFile" fileName="logs/application.log"
                     filePattern="logs/%d{YYYY-MM}/application.%d{dd-MMM}-%i.log.gz">
            <PatternLayout>
                <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Logger name="com.example" level="debug" additivity="false">
            <AppenderRef ref="LogToRollingFile"/>
            <AppenderRef ref="LogToConsole"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToRollingFile"/>
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

private static Logger logger = LogManager.getLogger();

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;

public class Log4j_XML_Example {

    WebDriver driver;

    By userName = By.name("username");
    By passWord = By.name("password");
    By loginBtn = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button");
    By loginTitle = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/h5");
    By dashboardPage = By.xpath("//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6");

    // Creating a logger
    private static Logger logger = LogManager.getLogger();

    @BeforeMethod
    public void setUp() {

        logger.info("Open a Chrome Web Browser");
        ChromeOptions options=new ChromeOptions();
        logger.info("Make the Web Browser full screen");
        options.addArguments("--start-maximized");
        driver=new ChromeDriver(options);
        logger.info("Wait for 10 sec");
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://opensource-demo.orangehrmlive.com/");
        logger.info("Open the application");
    }

    @Test(description = "This test validates title of login functionality", priority = 0)
    public void verifyLoginPageTitle() {

        logger.info("Verify the Login page title");
        String expectedTitle = driver.findElement(loginTitle).getText();

        logger.info("Expected Title :" + expectedTitle);
        Assert.assertTrue(expectedTitle.equalsIgnoreCase("Login"));
    }

    @Test(description = "This test validates  successful login to Home page", priority = 1)
    public void verifyloginPage() {

        logger.info("Enter Username");
        driver.findElement(userName).sendKeys("Admin");

        logger.info("Enter Password");
        driver.findElement(passWord).sendKeys("admin123");

        driver.findElement(loginBtn).submit();

        logger.info("New page - Dashboard is opened");
        String newPageText = driver.findElement(dashboardPage).getText();

        logger.info("Heading of new page :" + newPageText);
        Assert.assertTrue(newPageText.contains("Dashboard"));

    }

    @AfterMethod
    public void teardown() {

        logger.info("Close the webpage");
        driver.quit();
    }

}

How to download and install Apache POI

HOME

This tutorial describes how to download and install Apache POI.

Selenium does not have an inbuilt method to read data from an Excel File. However, there are various libraries in JAVA that help in reading/writing data from Excel files. Apache POI is one of the most used libraries, which provides various classes and methods to read/write data from various formats of Excel files(xls, xlsx etc).

What is Apache POI?

Apache POI, where POI stands for (Poor Obfuscation Implementation)  is the Java API for Microsoft Documents that offers a collection of Java libraries that helps us to read, write, and manipulate different Microsoft files such as Excel sheets, PowerPoint, and Word files.

Download Apache POI

Step 1To download Apache POI, go to its official site, here. Click on the Download as shown in the image. This link will navigate to the page showing the latest release of Apache POI.  The latest Apache POI version is 5.2.3. You can follow the same steps for any version of POI.

Step 2 This page shows the latest Apache POI Release Artifacts. Here, you can see POI 5.0.0 is the latest one. Download any one of the Binary Distribution options. One option is .ztar.gz and another option is .zip. I have selected .zip option.

Step 3 After clicking on the link, it navigates to another page as shown below. I have used the highlighted link to download the POI library files.

Step 4 Once POI.zip is downloaded and extracted, this is how the folder looks like

How to add POI libraries in Eclipse?

Step 1 Below is the Java project present in Eclipse.

Step 2 To add POI libraries to this project, Right-click on the project, hover over the Build path, select Configure Build Path.

Step 3  It will open the “Properties” of the project. After that, select the Libraries tab. Finally, click on the Add External JARs as highlighted below.

Step 4 Select the JARs in the parent folder of the unzipped POI files. Subsequently, click on the Open button to include them in the Eclipse project.

Step 5 – Next, select the JARs under the ooxml-lib folder in the unzipped POI folder as highlighted below:

Step 6 – Select the JARs under the lib folder in the unzipped POI folder as highlighted below.

Step 7 – After that, once all the POI JARs add, click on the Apply and Close button as highlighted below.

Step 8 – Once all the POI libraries successfully install in the Eclipse project, they will reflect under the Referenced Libraries folder in the left pane of the Eclipse project structure, as shown below:

How to add POI libraries to Maven Java Project

You can add the poi and poi-ooxml jar files to the Maven project by mentioning the dependencies in pom.xml.

 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.0.0</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>

You need to make sure that these two dependencies should be of the same version.

That’s it! We have downloaded and installed Apache POI.

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

How to save Log4j 2 logs in output file using properties file

HOME

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

  <groupId>com.example</groupId>
  <artifactId>Log4j2_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <selenium.version>4.15.0</selenium.version>
    <testng.version>7.8.0</testng.version>
    <log4j.version>3.0.0-alpha1</log4j.version>
    <maven.compiler.version>3.11.0</maven.compiler.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.surefire.failsafe.version>3.1.2</maven.surefire.failsafe.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>

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

    <!-- Log4j Dependency -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>${log4j.version}</version>
    </dependency>

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

  </dependencies>

  <build>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.failsafe.version}</version>
        <configuration>
          <skipTests>false</skipTests>
          <skip>false</skip>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>

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

</project>

# Root Logger
rootLogger = DEBUG, STDOUT, LogToFile

# Direct log messages to stdout
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

# Direct log messages to File
appender.file.type = File
appender.file.name = LogToFile
appender.file.fileName=logs/app.log
appender.file.layout.type=PatternLayout
appender.file.layout.pattern=[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

private static Logger logger = LogManager.getLogger();

package com.example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;

public class Log4j_XML_Example {

    WebDriver driver;

    By userName = By.name("username");
    By passWord = By.name("password");
    By loginBtn = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button");
    By loginTitle = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/h5");
    By dashboardPage = By.xpath("//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6");

    // Creating a logger
    private static Logger logger = LogManager.getLogger();

    @BeforeMethod
    public void setUp() {

        logger.info("Open a Chrome Web Browser");
        ChromeOptions options=new ChromeOptions();
        options.addArguments("--start-maximized");
        driver=new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://opensource-demo.orangehrmlive.com/");
        logger.info("Open the application");
    }

    @Test(description = "This test validates title of login functionality", priority = 0)
    public void verifyLoginPageTitle() {

        logger.info("Verify the Login page title");
        String expectedTitle = driver.findElement(loginTitle).getText();

        logger.info("Actual Title :" + expectedTitle);
        Assert.assertTrue(expectedTitle.equalsIgnoreCase("Login"));
    }

    @Test(description = "This test validates  successful login to Home page", priority = 1)
    public void verifyloginPage() {

        logger.info("Enter Username");
        driver.findElement(userName).sendKeys("Admin");

        logger.info("Enter Password");
        driver.findElement(passWord).sendKeys("admin123");

        driver.findElement(loginBtn).submit();

        logger.info("New page - Dashboard is opened");
        String newPageText = driver.findElement(dashboardPage).getText();

        logger.info("Heading of new page :" + newPageText);
        Assert.assertTrue(newPageText.contains("Dashboard"));

    }

    @AfterMethod
    public void teardown() {

        logger.info("Close the webpage");
        driver.quit();
    }

}

Log4j 2 Tutorials

HOME

Cucumber Tutorial – How to setup Cucumber with Eclipse

HOME

In the previous tutorials, we discussed BDD (Behaviour Driven Development) and GherkinCucumber is one such open-source tool, which supports Behaviour 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, we will set up Cucumber with Eclipse

Implementation Steps

1. Download and Install Java

Java is a robust programming language. Java is a general-purpose programming language that is concurrent; class-based and object-oriented language. Java follows the concept of “write once and run anywhere (WORA)” which means that compiled Java code can be run on all different platforms that support Java without the need for recompilation. Cucumber supports the Java platform for execution. Click here to know How to install Java.

2. Download and Start Eclipse

Eclipse is an Integrated Development Environment (IDE). It contains a base workspace and an extensible plug-in system for customizing the environment. To download Eclipse, please refer to this tutorial – How to install Eclipse.

3. Maven –  How to install Maven on Windows 

Apache Maven is a software project management and comprehension tool. It uses the concept of a project object model (POM), Maven can manage a project’s build, reporting, and documentation from a central piece of information. MAVEN helps us in creating the project structure and managing and downloading the dependencies. We need to define the required dependencies in pom.xml. To install Maven on Windows, please refer to this tutorial – How to install Maven.

4. Install Cucumber Eclipse Plugin

The Cucumber plugin is an Eclipse plugin that allows eclipse to understand the Gherkin syntax. Cucumber Eclipse Plugin highlights the keywords present in Feature File. To install Cucumber Eclipse Plugin, please refer to this tutorial – How to install Cucumber Eclipse Plugin

5. Configure Cucumber with Maven

Step 1 – Create a new Maven Project.

Click here to know the steps to create a new Maven project –  How to create a Maven project.

Step 2 – Open pom.xml of the project
       

Step 3 − Add dependency for selenium

This will indicate to Maven that Selenium jar files are to download from the central repository to the local repository.                                                                             

Open pom.xml in the edit mode, create dependencies tag (), inside the project tag.                   

 <!-- Selenium -->
 <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>4.15.0</version>
 </dependency>

Step 4 –  Add dependency for Cucumber-Java

This will indicate Maven, which Cucumber files are to be downloaded from the central repository to the local repository.  Create one more dependency tag.

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>7.14.0</version>
</dependency>

Step 5 – Add dependency for Cucumber-JUnit

This will indicate Maven, which Cucumber JUnit files are to download from the central repository to the local repository. Create one more dependency tag. 

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>7.14.0</version>
    <scope>test</scope>
</dependency>

Step 6 –  Add dependency for JUnit

This will indicate Maven, which JUnit files are to be downloaded from the central repository to the local repository. Create one more dependency tag.

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

Below is the screenshot which shows that Maven Project called Cucumber_JUnit4_Demo.

After adding the above mention dependencies, pom.xml looks like the image below

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

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

</project>

After adding the dependencies and then building the project, the below image shows the entire jar files added to the Maven Dependency.

Congratulations!! We are done with the setup of the Cucumber in Eclipse. Happy Learning.

Integration Testing of Springboot with Cucumber and JUnit4

Last Updated On

HOME

In this tutorial, I am going to build an automation framework to test the Springboot application with Cucumber, Rest Assured, and JUnit4.

Table of Contents

  1. What is Springboot?
  2. What is Cucumber?
  3. Dependency List
  4. Test Automation Framework Implementation
    1. Add SpringbootTest, Rest-Assured, and Cucumber dependencies to the project
    2. Create a directory src/test/resources and create a feature file under src/test/resources
    3. Create the Step Definition class or Glue Code for the Test Scenario under src/test/java
    4. Create a Cucumber Runner class under src/test/java
    5. Run the tests from JUnit
    6. Run the tests from Command Line
    7. Cucumber Report Generation

What is Springboot?

Spring Boot is an open-source micro framework maintained by a company called Pivotal. It provides Java developers with a platform to get started with an auto-configurable production-grade Spring application. With it, developers can get started quickly without losing time on preparing and configuring their Spring application.

What is Cucumber?

A cucumber is a software tool that supports behavior-driven development (BDD). Cucumber can be defined as a testing framework, driven by plain English. It serves as documentation, automated tests, and development aid – all in one.

Dependency List

  1. Springboot – 2.5.2
  2. Cucumber – 6.10.4
  3. Java 11
  4. JUnit – 4.13.2
  5. Maven – 3.8.1
  6. RestAssured – 4.3.3
  7. JUnit Vintage Engine (To run the tests through command line)

Below is the structure of a SpringBoot application project.

Below are various Java classes present in a SpringBoot REST Application.

  • SpringBootRestServiceApplication.java – The Spring Boot Application class is generated with Spring Initializer. This class acts as the launching point for the application.
  • pom.xml – This contains all the dependencies needed to build this project. 
  • Student.java – This is JPA Entity for Student class
  • StudentRepository.java – This is JPA Repository for Student. This is created using Spring Data JpaRepository.
  • StudentController.java – Spring Rest Controller exposing all services on the student resource.
  • CustomizedExceptionHandler.java – This implements global exception handling and customizes the responses based on the exception type.
  • ErrorDetails.java – Response Bean to use when exceptions are thrown from API.
  • StudentNotFoundException.java – Exception thrown from resources when the student is not found.
  • data.sql –  Data is loaded from data.sql into the Student table. Spring Boot would execute this script after the tables are created from the entities.
  • application.properties – Spring Boot automatically loads the application.properties whenever it starts up. You can de-reference values from the property file in the Java code through the environment.

Student.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class Student {
    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    @Size(min = 4, message = "Name should have atleast 4 characters")
    private String name;

    @NotBlank(message = "passportNumber is mandatory")
    private String passportNumber;

    public Student() {
        super();
    }

    public Student(Long id, String name, String passportNumber) {
        super();
        this.id = id;
        this.name = name;
        this.passportNumber = passportNumber;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassportNumber() {
        return passportNumber;
    }

    public void setPassportNumber(String passportNumber) {
        this.passportNumber = passportNumber;
    }
}

StudentController

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
import java.net.URI;
import java.util.List;
import java.util.Optional;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@RestController
public class StudentController {

    @Autowired
    private StudentRepository studentRepository;

    @GetMapping("/students/{id}")
    public EntityModel<Student> retrieveStudent(@PathVariable long id) {
        Optional<Student> student = studentRepository.findById(id);

        if (!student.isPresent())
            throw new StudentNotFoundException("id-" + id);

        EntityModel<Student> resource = EntityModel.of(student.get());

        WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllStudents());

        resource.add(linkTo.withRel("all-students"));

        return resource;
    }
}

StudentRepository

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long>{

}

SpringBootRestServiceApplication

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootRestServiceApplication {

    public static void main(String[] args) {

        SpringApplication.run(SpringBootRestServiceApplication.class, args);
    }

}

application.properties

spring.jpa.defer-datasource-initialization=true

data.sql

insert into student values(10001,'Annie', 'E1234567');
insert into student values(10002,'John', 'A1234568');
insert into student values(10003,'David','C1232268');

Test Automation Framework Implementation

Step 1 – Add SpringbootTest, Rest-Assured, and Cucumber dependencies to the project

To Test a SpringBoot Application, we are using SpringBoot Test, JUnit, Cucumber, and Rest Assured. Below mentioned dependencies are added in POM.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>4.3.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>6.10.4</version>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>6.10.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-spring</artifactId>
            <version>6.10.4</version>
            <scope>test</scope>
        </dependency>

Step 2 – Create a directory src/test/resources and create a feature file under src/test/resources

By default, the Maven project has src/test/java directory only. Create a new directory under src/test with the name of resources. Create a folder name as Features within src/test/resources directory.

Create a feature file to test the Springboot application.

Below is a sample feature file.

Feature: Verify springboot application using Cucumber

@ReceiveUserDetails
Scenario Outline: Send a valid Request to get user details
Given I send a request to the URL "/students" to get user details
Then the response will return status 200 and id <studentID> and names "<studentNames>" and passport_no "<studentPassportNo>"

Examples:
|studentID    |studentNames  |studentPassportNo|
|10001        |Annie         |E1234567         |
|10002        |John          |A1234568         |
|10003        |David         |C1232268         |

Step 3 – Create the Step Definition class or Glue Code for the Test Scenario under src/test/java

The corresponding step definition file of the above feature file is shown below.

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.spring.CucumberContextConfiguration;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;

@CucumberContextConfiguration
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringbootCucumberTestDefinitions {

    private final static String BASE_URI = "http://localhost";

    @LocalServerPort
    private int port;

    private ValidatableResponse validatableResponse;

    private void configureRestAssured() {
        RestAssured.baseURI = BASE_URI;
        RestAssured.port = port;
    }

    protected RequestSpecification requestSpecification() {
        configureRestAssured();
        return given();
    }

    @Given("I send a request to the URL {string} to get user details")
    public void iSendARequest(String endpoint) throws Throwable {
        validatableResponse = requestSpecification().contentType(ContentType.JSON)
                .when().get(endpoint).then();
        System.out.println("RESPONSE :"+validatableResponse.extract().asString());
    }

    @Then("the response will return status {int} and id {int} and names {string} and passport_no {string}")
    public void extractResponse(int status, int id, String studentName,String passportNo) {
        validatableResponse.assertThat().statusCode(equalTo(status))
                .body("id",hasItem(id)).body(containsString(studentName))
                .body(containsString(passportNo));

    }

}

The @CucumberContextConfiguration annotation tells Cucumber to use this class as the test context configuration for Spring. It is imported from:-

import io.cucumber.spring.CucumberContextConfiguration;

With the @SpringBootTest annotation, Spring Boot provides a convenient way to start up an application context to be used in a test.  It is imported from package:-

import org.springframework.boot.test.context.SpringBootTest;

By default, @SpringBootTest does not start the webEnvironment to refine further how your tests run. It has several options: MOCK(default), RANDOM_PORT, DEFINED_PORT, NONE.

RANDOM_PORT loads a WebServerApplicationContext and provides a real web environment. The embedded server is started and listens on a random port. LocalServerPort is imported from package:-

import org.springframework.boot.web.server.LocalServerPort;

The assertions are imported from the Hamcrest package:-

import static org.hamcrest.Matchers.*;

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

A runner will help us to run the feature file and act as an interlink between the feature file and StepDefinition Class. To know more about Runner, refer to this link. The TestRunner should be created within the directory src/test/java.

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"}, glue = { "com.example.demo.definitions"})

public class CucumberRunnerTests {
}

The @CucumberOptions annotation is responsible for pointing to the right feature package, configuring the plugin for a better reporting of tests in the console output, and specifying the package where extra glue classes may be found. We use it to load configurations and classes that are shared between tests.

Step 5 – Run the tests from JUnit

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

In case you are using IntelliJ, select “Run CucumberRunnerTests“.

SpringBootTest creates an application context containing all the objects we need for the Integration Testing It, starts the embedded server, creates a web environment, and then enables methods to do Integration testing.

Step 6 – Run the tests from the Command Line

To run the tests from the command line, we need to add junit-vintage-engine dependency. Starting with Spring Boot 2.4, JUnit 5’s vintage engine has been removed from the spring-boot-starter-test. If we still want to write tests using JUnit 4, we need to add the following Maven dependency:

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

Use the below command to run the tests:-

mvn clean test

Step 7 – Cucumber Report Generation

To get Cucumber Test Reports, add cucumber.properties under src/test/resources and add the below instruction in the file. To know more about Cucumber Report Service, refer to this tutorial.

cucumber.publish.enabled=true

Below is the image of the report generated after the completion of the execution. This report can be saved on GitHub for future use.

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

SpringBoot WireMock
SpringBoot Dependency Injection using Autowired
 Testing of Gradle SpringBoot Application with Serenity, Cucumber and JUnit4
Testing of SpringBoot Application with Serenity BDD, Cucumber and JUnit5 
 How to run SpringBoot tests with GitHub Actions

How to connect to SQL Server using Java

HOME

jdbc:<driver protocol>:<driver connection details>
MS MySql Server - jdbc:odbc:DemoDSN
MySQL - jdbc:mysql://localhost:3306/demodb
Oracle - jdbc:orac;e:thin@myserver:1521:demodb

String dbUrl = "jdbc:mysql://localhost:3306/demo";
String username = "student";
String password = "student";

Connection conn = DriverManager.getConnection(dbUrl,username,password)
Statement stmt = conn.createStatement();

ResultSet result = stmt.executeQuery("select * from employee");

 java.sql and javax.sql
<dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <version>8.2.0</version>
</dependency>

import java.sql.*;

public class JdbcTest {

    public static void main(String[] args) throws SQLException {

        Connection conn;
        Statement stmt = null;
        ResultSet result = null;

        String dbUrl = "jdbc:mysql://localhost:3306/demo";
        String username = "student";
        String password = "student1$";

        try {
            //Get a connection to database
            conn = DriverManager.getConnection(dbUrl, username, password);

            System.out.println("Database connection is successful\n");

            //Create a statement
            stmt = conn.createStatement();

            //Execute the SQL Query
            result = stmt.executeQuery("Select * from employees");

            //Process the result set
            while (result.next()) {
                System.out.println("First_Name :" + result.getString("first_name") + " , " + ("Last_Name :" + result.getString("last_name")));

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

create database if not exists demo;

use demo;

drop table if exists employees;

CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `last_name` varchar(64) DEFAULT NULL,
  `first_name` varchar(64) DEFAULT NULL,
  `email` varchar(64) DEFAULT NULL,
  `department` varchar(64) DEFAULT NULL,
  `salary` DECIMAL(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (1,'Doe','John','john.doe@foo.com', 'HR', 55000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (2,'Public','Mary','mary.public@foo.com', 'Engineering', 75000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (3,'Queue','Susan','susan.queue@foo.com', 'Legal', 130000.00);

INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (4,'Williams','David','david.williams@foo.com', 'HR', 120000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (5,'Johnson','Lisa','lisa.johnson@foo.com', 'Engineering', 50000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (6,'Smith','Paul','paul.smith@foo.com', 'Legal', 100000.00);

INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (7,'Adams','Carl','carl.adams@foo.com', 'HR', 50000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (8,'Brown','Bill','bill.brown@foo.com', 'Engineering', 50000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (9,'Thomas','Susan','susan.thomas@foo.com', 'Legal', 80000.00);

INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (10,'Davis','John','john.davis@foo.com', 'HR', 45000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (11,'Fowler','Mary','mary.fowler@foo.com', 'Engineering', 65000.00);
INSERT INTO `employees` (`id`,`last_name`,`first_name`,`email`, `department`, `salary`) VALUES (12,'Waters','David','david.waters@foo.com', 'Legal', 90000.00);

select * from demo.employees;

Integration of Serenity with Rest Assured

HOME

In this tutorial, I will explain the Integration of Serenity BDD with Rest Assured for the testing of RestFul API.

What is Serenity BDD?

Serenity BDD is an open-source library that aims to make the idea of living documentation a reality.

What is Rest Assured?

Rest Assured is one of the most powerful libraries for testing RESTful API using Java language. Rest-Assured is a Java-based library that is used to test RESTful Web Services. This library behaves like a headless Client to access REST web services. The rest-Assured library also provides the ability to validate the HTTP Responses received from the server. 

Prerequisite

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

Dependency List

  1. Java 17
  2. Maven – 3.9.5
  3. Serenity – 4.0.18
  4. Serenity Rest Assured – 4.0.18
  5. Rest Assured – 5.3.2
  6. JUnit – 4.13.2
  7. Maven Surefire Plugin – 3.1.2
  8. Maven Failsafe Plugin – 3.1.2
  9. Maven Compiler Plugin – 3.11.0

Project Structure

Step 1 – Update the Properties section in Maven pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <serenity.version>4.0.18</serenity.version>
    <serenity.maven.version>4.0.18</serenity.maven.version>
    <junit.version>4.13.2</junit.version>
    <rest.assured.version>5.3.2</rest.assured.version>
    <json.version>20231013</json.version>
    <maven.surefire.plugin.version>3.1.2</maven.surefire.plugin.version>
    <maven.failsafe.plugin.version>3.1.2</maven.failsafe.plugin.version>
    <maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <tags></tags>
  </properties>

Step 2 – Add dependencies to POM.xml

<dependencies>
   <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-core</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-junit</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>
      
        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-screenplay-rest</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-rest-assured</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>${rest.assured.version}</version>
            <scope>test</scope>
        </dependency>
         
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>  
  
       <dependency>
           <groupId>org.json</groupId>
           <artifactId>json</artifactId>
           <version>${json.version}</version>
        </dependency> 
        
    </dependencies>

Step 3 – Update the Build Section of pom.xml

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven.surefire.plugin.version}</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${maven.failsafe.plugin.version}</version>
                <configuration>
                    <includes>
                        <include>**/*.java</include>
                        <include>**/*.Tests</include>
                    </includes>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
           <plugin>
               <groupId>net.serenity-bdd.maven.plugins</groupId>
               <artifactId>serenity-maven-plugin</artifactId>
               <version>${serenity.version}</version>
               <dependencies> 
                  <dependency>
                       <groupId>net.serenity-bdd</groupId>
                       <artifactId>serenity-single-page-report</artifactId>
                       <version>${serenity.version}</version>
                  </dependency>                
               </dependencies>
               <configuration>
                   <tags>${tags}</tags>
                   <reports>single-page-html</reports> 
               </configuration>
               <executions>
                  <execution>
                      <id>serenity-reports</id>
                      <phase>post-integration-test</phase>
                      <goals>
                          <goal>aggregate</goal>
                      </goals>
                   </execution>
               </executions>
           </plugin>
        </plugins>
    </build>

Step 4 – Create the Test Code in src/java/test directory

There are 2 ways to create the same test. One approach is to have a Definition file that contains all the test code as shown below.

package org.example.tests;

import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import org.json.JSONObject;
import org.junit.Test;

import static org.hamcrest.Matchers.equalTo;

public class Employee {
    private static final String URL = "https://reqres.in/api";
    public Response response;

    int id = 2;

    @Test
    public void verifyValidUser() {

        response = SerenityRest
                .given()
                .contentType("application/json")
                .header("Content-Type", "application/json")
                .when()
                .get(URL + "/users/" + id);

        SerenityRest.restAssuredThat(response -> response.statusCode(200)
                .body("data.id", equalTo(2))
                .body("data.email", equalTo("janet.weaver@reqres.in"))
                .body("data.first_name", equalTo("Janet"))
                .body("data.last_name", equalTo("Weaver")));

    }

    @Test
    public void verifyCreateUser() {
        JSONObject data = new JSONObject();

        data.put("name", "Test");
        data.put("job", "Test Architect");

        response = SerenityRest
                .given()
                .contentType("application/json")
                .header("Content-Type", "application/json")
                .body(data.toString())
                .when()
                .post(URL + "/users");

        SerenityRest.restAssuredThat(response -> response.statusCode(201)
                .body("name", equalTo("Test"))
                .body("job", equalTo("Test Architect")));

    }

}

Another approach is that all tests are split into reusable blocks called “steps“. The main principle of the BDD approach is that we are trying to keep complexity to a high-level human-readable level. First of all, let’s create a separate package to keep our steps. It is always better to keep them separate as it shows which classes contain reusable components. It is better to make steps smaller. So let’s make separate reusable steps from our tests:

package org.example.steps;

import io.restassured.response.Response;
import net.serenitybdd.annotations.Step;
import net.serenitybdd.rest.SerenityRest;
import org.json.JSONObject;

import static org.hamcrest.Matchers.equalTo;

public class EmployeeSteps {
    private static final String URL = "https://reqres.in/api";
    public Response response;

    @Step("Search user by id {0}")
    public void sendUser(int id) {
        response = SerenityRest
                .given()
                .contentType("application/json")
                .header("Content-Type", "application/json")
                .when()
                .get(URL + "/users/" + id);

    }

    @Step("Create a new user")
    public void createUser() {

        JSONObject data = new JSONObject();

        data.put("name", "Test");
        data.put("job", "Test Architect");

        response = SerenityRest
                .given()
                .contentType("application/json")
                .header("Content-Type", "application/json")
                .body(data.toString())
                .when()
                .post(URL + "/users");

    }

    @Step("Verify the status code {0}")
    public void verifyStatusCode(int expectedStatusCode) {
        SerenityRest.restAssuredThat(response -> response.statusCode(expectedStatusCode));
    }

    @Step("Verify the user id {0}")
    public void verifyId(int expectedId) {
        SerenityRest.restAssuredThat(response -> response.body("data.id", equalTo(expectedId)));
    }

    @Step("Verify the user first name {0}")
    public void verifyFirstName(String expectedFirstName) {

        SerenityRest.restAssuredThat(response -> response.body("data.first_name", equalTo(expectedFirstName)));
    }

    @Step("Verify the user last name {0}")
    public void verifyLastName(String expectedLastName) {
        SerenityRest.restAssuredThat(response -> response.body("data.last_name", equalTo(expectedLastName)));
    }

    @Step("Verify the user email {0}")
    public void verifyEmail(String expectedEmail) {
        SerenityRest.restAssuredThat(response -> response.body("data.email", equalTo(expectedEmail)));
    }

    @Step("Verify the new user name {0}")
    public void verifyNewUserName(String expectedName) {
        SerenityRest.restAssuredThat(response -> response.body("name", equalTo(expectedName)));
    }

    @Step("Verify the new user job {0}")
    public void verifyNewUserJob(String expectedJob) {
        SerenityRest.restAssuredThat(response -> response.body("job", equalTo(expectedJob)));
    }

}

Now our steps are ready. Let’s refactor the main class with our tests:

package org.example.tests;

import net.serenitybdd.annotations.Steps;
import net.serenitybdd.annotations.Title;
import net.serenitybdd.junit.runners.SerenityRunner;
import org.example.steps.EmployeeSteps;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(SerenityRunner.class)
public class EmployeeTests {
    @Steps
    EmployeeSteps employeeSteps;

    @Test
    @Title("Get User")
    public void verifyValidUser() {
        employeeSteps.sendUser(2);
        employeeSteps.verifyStatusCode(200);
        employeeSteps.verifyId(2);
        employeeSteps.verifyFirstName("Janet");
        employeeSteps.verifyLastName("Weaver");
        employeeSteps.verifyEmail("janet.weaver@reqres.in");

    }

    @Test
    @Title("Create User")
    public void createValidUser() {

        employeeSteps.createUser();
        employeeSteps.verifyStatusCode(201);
        employeeSteps.verifyNewUserName("Test");
        employeeSteps.verifyNewUserJob("Test Architect");

    }

}

One more important thing we added is the @RunWith(SerenityRunner.class)” annotation on top of the class. As we have now organized our structure to meet some basic Serenity principles, we are ready to run the test using Serenity. This time (after we added the mentioned annotation) these tests will be run using the “SerenityRunner”. For that we can use exactly the same command to run our tests:

mvn clean verify

The output of the above program is

In the console, you should find printed messages for tests to start. At the same time under the target directory you can find the HTML-generated report we were talking about before:

You can open the report in any browser:

If you click on any test you should see a detailed description of the test steps:

One of the most important features of the Serenity and REST Assured integration is that by using detailed reporting, you can easily validate all requests and response details even if you are not adding any logs inside tests. Like the example above, for each executed REST request you can click the button “REST Query” and get a detailed request and response description:

There is another very useful Serenity Report – Serenity Symmary.html

As you can see, Serenity and REST Assured provide you with a wonderful combination. REST Assured keeps API testing clean and easy to maintain, while Serenity gives you outstanding test reporting and flexibility in running and grouping your tests inside a test suite.

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

How to Clone a project from GitLab using Eclipse

HOME

What is GitLab?

GitLab is a web-based Git repository that provides free open and private repositories, issue-following capabilities, and wikis. It is a complete DevOps platform that enables professionals to perform all the tasks in a project—from project planning and source code management to monitoring and security.

In this tutorial, I will explain how we can clone a project from GitLab in Eclipse.

Implementation Steps

Step 1 – Go to GitLab and select the project which you want to clone. Click on the blue color “Clone” button then copy the hyperlink as shown in the image. You can either Clone with SSH or Clone with HTTPS.

Step 2 – Open Eclipse and go to “File > Import” in eclipse as shown in the image.

Step 3 – A window will pop up in which select Git Folder. Under the Git folder, select the option – “Projects from Git(with smart import)” as shown in the image.

Click on the “NEXT” button.

Step 4 – A new window will pop up in which select the option –Clone URI” as shown in the image.

Click on the “NEXT” button.

Step 5 – Another window will pop up in which you have to paste the “GitLab Repository URL” and also “GitLab UserID and Password” and click on the “Next” button.

URI – This is the URL that we have cloned from GitLab in Step 1.
Host – gitlab.com
Repository path – path of the project in GitLab (This is auto-populated after entering URI)

Authentication
User – Username of GitLab
Password – password of GitLab

Step 6 – Select master and selectWhen fetching a commit, also fetch its tags.

Click on the “Next” button.

Step 7 –  Select the “Folder directory” in which you want to import the repository.

Click on the “Finish” button.

Step 8 – We have successfully imported the GitLab Repository as shown in the below image.

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