How to handle HTTP Query Parameters using REST Assured

HOME

https://reqres.in/api/users?page=2
import org.junit.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.equalTo;

public class ParamDemo {


    @Test
    public void verifyQueryParam() {

        String endpoint = "https://reqres.in/api/";

        // Given
        given()
                .queryParam("page", "2")

                // When
                .when()
                .get(endpoint + "users/")

                // Then
                .then()

                // To verify the response body
                .body("page", equalTo(2))
                .body("per_page", equalTo(6))
                .body("total_pages", equalTo(2));

    }
}

How to perform multiple assertions in Rest Assured?

HOME

  @Test
   public void verifyHardAssertion() {

      // Given
      given()

              // When
              .when()
              .get("https://reqres.in/api/users/2")

              // Then
              .then()

              // To verify the response body
              .body("data.email", equalTo("janet.weaver@reqres12.in"))
              .body("data.first_name", equalTo("Janet1"))
              .body("data.last_name", equalTo("Weaver"));

    }

 @Test
  public void verifySoftAssertion() {

      // Given
      given()

              // When
              .when()
              .get("https://reqres.in/api/users/2")

              // Then
              .then()

              // To verify the response body
              .body("data.email", equalTo("janet.weaver@reqres12.in"),
                        "data.first_name", equalTo("Janet1"),
                        "data.last_name", equalTo("Weaver"));

    }
}

Integration of Serenity with Cucumber and JUnit5

HOME

In the previous tutorial, I explained the Serenity BDD with Cucumber for Web Application using Junit4. In this tutorial, I will explain the same Test Framework using Serenity, Cucumber, and JUnit5. This tutorial gives a clear picture of the initial setup of a BDD Framework.

What is JUnit5?

JUnit 5 is composed of several different modules from three different sub-projects.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also defines the TestEngine API for developing a testing framework that runs on the platform.

JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a TestEngine for running Jupiter based tests on the platform.

JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests on the platform. It requires JUnit 4.12 or later to be present on the class/module path.

JUnit5 is not completely integrated with Serenity with Cucumber. So, it is advisable to use jupiter-vintage-engine for the Cucumber TestRunner classes.

Dependency List:

  1. Serenity – 4.0.28
  2. JUnit Jupiter – 5.10.1
  3. JUnit Vintage – 5.10.1
  4. JUnit Platform Suite – 1.10.1
  5. Cucumber JUnit Platform – 7.15.0
  6. Java 17
  7. Maven – 3.9.5
  8. Maven Compiler Plugin – 3.11.0
  9. Maven Surefire Plugin – 3.2.1
  10. Maven FailSafe Plugin – 3.2.1

Implementation Steps

Step 1- Download and Install Java

Click here to know How to install Java.

Step 2 – Download and setup Eclipse IDE on the system

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

Step 3 – Setup Maven and create a new Maven Project

Click here to know How to install Maven.

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

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

Step 4 – Update Properties section in Maven pom.xml

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <serenity.version>4.0.28</serenity.version>
        <junit.jupiter.version>5.10.1</junit.jupiter.version>
        <junit.vintage.version>5.10.1</junit.vintage.version>
        <junit-platform-suite.version>1.10.1</junit-platform-suite.version>
        <cucumber-junit-platform-engine.version>7.15.0</cucumber-junit-platform-engine.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>
        <maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
        <maven.failsafe.plugin.version>3.2.1</maven.failsafe.plugin.version>
        <tags></tags>
  </properties>

Step 5 – Add repositories and pluginRepository to Maven pom.xml

 <repositories>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>bintray</name>
            <url>https://jcenter.bintray.com</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>bintray-plugins</name>
            <url>https://jcenter.bintray.com</url>
        </pluginRepository>
    </pluginRepositories>

Step 6 – Add Serenity, Serenity Cucumber, and JUnit dependencies to POM.xml

<dependencies>
        <!-- JUnit 5 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>${junit.vintage.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Serenity -->
         <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-cucumber</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-screenplay-webdriver</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>

     <dependency>
         <groupId>org.junit.platform</groupId>
         <artifactId>junit-platform-suite</artifactId>
         <version>${junit-platform-suite.version}</version>
         <scope>test</scope>
     </dependency>

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

    </dependencies>

Step 7 – 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>
                    </includes>
                    <parallel>methods</parallel>
                    <useUnlimitedThreads>true</useUnlimitedThreads>
                </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>
</project>

<?xml version="1.0" encoding="UTF-8"?>

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

  <groupId>com.example</groupId>
  <artifactId>SerenityCucumberJunit5Demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>SerenityCucumberJunit5Demo</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <serenity.version>4.0.28</serenity.version>
        <junit.jupiter.version>5.10.1</junit.jupiter.version>
        <junit.vintage.version>5.10.1</junit.vintage.version>
        <junit-platform-suite.version>1.10.1</junit-platform-suite.version>
        <cucumber-junit-platform-engine.version>7.15.0</cucumber-junit-platform-engine.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>
        <maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
        <maven.failsafe.plugin.version>3.2.1</maven.failsafe.plugin.version>
        <tags></tags>
  </properties>
  
  <repositories>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>bintray</name>
            <url>https://jcenter.bintray.com</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>bintray-plugins</name>
            <url>https://jcenter.bintray.com</url>
        </pluginRepository>
    </pluginRepositories>

 <dependencies>
        <!-- JUnit 5 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>${junit.vintage.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Serenity -->
         <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-cucumber</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>net.serenity-bdd</groupId>
            <artifactId>serenity-screenplay-webdriver</artifactId>
            <version>${serenity.version}</version>
            <scope>test</scope>
        </dependency>

     <dependency>
         <groupId>org.junit.platform</groupId>
         <artifactId>junit-platform-suite</artifactId>
         <version>${junit-platform-suite.version}</version>
         <scope>test</scope>
     </dependency>

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

    </dependencies>

    <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>
                    </includes>
                    <parallel>methods</parallel>
                    <useUnlimitedThreads>true</useUnlimitedThreads>
                </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>
</project>

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

The purpose of the Feature keyword is to provide a high-level description of a software feature, and to group related scenarios. To know more about the Feature file, please refer this tutorial.

Feature: Login to HRM  

   @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 successfully
    
    @InValidCredentials    
    Scenario Outline: Login with invalid credentials
   
    Given User is on Home page
    When User enters username as '<username>'
    And User enters password as '<password>'
    Then User should be able to see error message '<errorMessage>'
      
   Examples:
    |username   |password       |errorMessage               |
    |admin        |admin            |Invalid credentials        |
    |abc            |admin123       |Invalid credentials        |
    |abc            |abc123           |Invalid credentials         |
    |1$£"          | 45£"%           |Invalid credentials        |
 
   @ForgetPassword  
   Scenario: Verify Forget Password Functionality
   
    Given User is on Home page
    When User clicks on Forgot your password link
    Then User should be able to see new page which contains Reset Password button

Step 9 – Create junit-platform.properties file under src/test/resources (optional)

This is an optional step. Cucumber of version 6.7 and above provides the functionality to generate a beautiful cucumber report. For this, it is needed to add a file junit-platform.properties under src/test/resources.

cucumber.publish.enabled = true

Step 10 – Create the Step Definition class or Glue Code

A Step Definition is a Java method with an expression that links it to one or more Gherkin steps. When Cucumber executes a Gherkin step in a scenario, it will look for a matching step definition to execute. You can have all of your step definitions in one file, or in multiple files.

LoginPageDefinitions

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.example.SerenityCucumberJunit5Demo.steps.StepDashboardPage;
import com.example.SerenityCucumberJunit5Demo.steps.StepForgetPasswordPage;
import com.example.SerenityCucumberJunit5Demo.steps.StepLoginPage;

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import net.serenitybdd.annotations.Steps;


public class LoginPageDefinitions {

	@Steps
	StepLoginPage loginPage;

	@Steps
	StepDashboardPage dashPage;

	@Steps
	StepForgetPasswordPage forgetpasswordPage;

	@Given("User is on Home page")
	public void openApplication() {
		loginPage.open();
	}

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

		loginPage.inputUserName(userName);
	}

	@When("User enters password as {string}")
	public void enterPassword(String passWord) {
		loginPage.inputPassword(passWord);
		loginPage.clickLogin();
	}

	@Then("User should be able to login successfully")
	public void clickOnLoginButton() {
		dashPage.loginVerify();
	}

	@Then("User should be able to see error message {string}")
	public void unsucessfulLogin(String expectedErrorMessage) {
		String actualErrorMessage = loginPage.errorMessage();

		System.out.println("Actual Error Message :" + actualErrorMessage);

		assertEquals(expectedErrorMessage, actualErrorMessage);
	}

	@When("User clicks on Forgot your password link")
	public void clickForgetPasswordLink() {
		loginPage.clickForgetPasswordLink();
	}

	@Then("User should be able to see new page which contains Reset Password button")
	public void verifyForgetPasswordPage() {

		assertTrue(forgetpasswordPage.ForgetPasswordPage());
	}
}

Assertions in JUnit-Vintage Engine are imported from the below package:-

import static org.junit.jupiter.api.Assertions.*;

DashboardPageDefinitions

import com.example.SerenityCucumberJunit5Demo.steps.StepDashboardPage;
import net.serenitybdd.annotations.Step;
import net.serenitybdd.annotations.Steps;

public class DashboardPageDefinitions {

	@Steps
	StepDashboardPage dashPage;

	@Step
	public void verifyAdminLogin() {
		dashPage.loginVerify();
	}
}

The corresponding Test Step classes are – StepLoginPage and StepDashboardPage.

There are multiple ways to identify a web element on the web page – one of the ways is to use @FindBy or $(By.).

I prefer to use @FindBy as I need not find the same element multiple times. Using @FindBy, I have identified a web element and defined a WebElementFacacde for the same which is reusable.

StepLoginPage

import net.serenitybdd.annotations.Step;
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;


public class StepLoginPage extends PageObject {

	@FindBy(name = "username")
	WebElementFacade username;

	@FindBy(name = "password")
	WebElementFacade password;

	@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
	WebElementFacade submitButton;

	@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
	WebElementFacade errorMessage;

	@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[4]/p")
	WebElementFacade linkText;

	@Step("Enter Username")
	public void inputUserName(String userName) {
		username.sendKeys((userName));
	}

	@Step("Enter Password")
	public void inputPassword(String passWord) {
		password.sendKeys((passWord));
	}

	@Step("Click Submit Button")
	public void clickLogin() {
		submitButton.click();
	}

	@Step("Error Message on unsuccessful login")
	public String errorMessage() {
		String actualErrorMessage = errorMessage.getText();
		System.out.println("Actual Error Message :" + actualErrorMessage);

		return actualErrorMessage;
	}

	@Step("Click Forget Password Link")
	public void clickForgetPasswordLink() {
		linkText.click();

		System.out.println("Clicked on Forgot Password Link");
	}

}

StepDashboardPage

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import net.serenitybdd.annotations.Step;
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;

public class StepDashboardPage extends PageObject {

	@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6")
	WebElementFacade dashboardText;

	@Step("Successful login")
	public void loginVerify() {
		String dashboardTitle = dashboardText.getText();
		assertThat(dashboardTitle, containsString("Dashboard"));
	}
}

StepForgetPasswordPage

import net.serenitybdd.annotations.Step;
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;

public class StepForgetPasswordPage extends PageObject {

	@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/div/form/h6")
	WebElementFacade forgetLink;

	@Step("Verify Forget Password Page ")
	public boolean ForgetPasswordPage() {
		Boolean resetPasswordButton = forgetLink.isDisplayed();

		return resetPasswordButton;
	}
}

Step 11 – Create a Serenity-Cucumber Runner class

Cucumber runs the feature files via JUnit and needs a dedicated test runner class to actually run the feature files. When you run the tests with Serenity, you use the CucumberWithSerenity test runner. You also need to use the @CucumberOptions class to provide the root directory where the feature files can be found.

import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;

import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("/features")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.SerenityCucumberJunit5Demo.definitions")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "io.cucumber.core.plugin.SerenityReporterParallel,pretty,timeline:build/test-results/timeline")

public class SerenityRunnerTest {

}

Step 12 – Create serenity.conf file under src/test/resources

The serenity configuration file is used to configure the drivers so the test cases can run successfully. This file contains an operating system-specific binary. The binary file sits between your test and the browser. It acts as an intermediary, an interface between your tests and the browser you are using.

You can also configure the webdriver.base.url property for different environments in the serenity.conf configuration file.

headless.mode = false

webdriver {
  driver = chrome
  capabilities {
    browserName = "chrome"
    acceptInsecureCerts = true
    "goog:chromeOptions" {
      args = ["remote-allow-origins=*","test-type", "no-sandbox", "ignore-certificate-errors", "--window-size=1000,800",
        "incognito", "disable-infobars", "disable-gpu", "disable-default-apps", "disable-popup-blocking",
        "disable-dev-shm-usage", "disable-extensions", "disable-web-security", "disable-translate", "disable-logging"]
    }
  }
}



#
# Define drivers for different platforms. Serenity will automatically pick the correct driver for the current platform
#

environments {
  default {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/"
  }
  dev {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/dev"
  }
  staging {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/staging"
  }
  prod {
    webdriver.base.url = "https://opensource-demo.orangehrmlive.com/prod"
  }
}

Step 13 – Create serenity.properties file at the root of the project

serenity.project.name = Serenity and Cucumber and JUnit5 Demo

Step 14 – Run the tests from Command Line

Open the command line and go to the location where pom.xml of the project is present and type the below command.

mvn clean verify

Step 15 – Test Execution Status

The image displayed above shows the execution status.

The feature file contains 3 test cases. Test Case 2 is a Test Scenario that has 4 examples. So, in total we have 6 tests. This information is clearly mentioned in the new version of Serenity.

Step 16 – Serenity Report Generation

The best part about Serenity is the report generation by it. The Reports contain all possible types of information, you can think of with minimal extra effort. There are multiple types of reports are generated. We are interested in index.html and serenity-summary.html. To know more about Serenity Reports, please refer to tutorials for Index.html and Serenity-Summary.html. Below is the new Serenity Report.

  1. index.html

2. serenity-summary.html

Step 17 – Cucumber Report Generation (Optional)

Every Test Execution generates a Cucumber Report (Version 6.7.0) and above as shown in the image.

Copy the URL and paste it to a browser and it shows the report as shown below:

To know more about Cucumber Reports, refer to this tutorial.

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

How to verify JSON response headers in Rest Assured?

HOME

import org.junit.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;

public class ResponseHeader {

    @Test
    public void verifyResponseHeader() {

      // Given
      given()

              // When
              .when()
              .get("https://reqres.in/api/users/2")

              // Then
              .then()
              .statusCode(200).statusLine("HTTP/1.1 200 OK")
              .log().all()
              .header("Content-Type" , "application/json; charset=utf-8")
              .header("Content-Encoding" , "gzip")
              .header("Server" , containsString("cloudflare"));

    }
}

Class and Object in Java

HOME

Let us consider the Phone as the object. The state of the Phone is coloured grey, and black, and types like IPhone, Samsung, and behaviour is calling, sending messages, and internet browsing.

public class Student {
          String Name;
}

How to create an Object?

To create an object, specify a class name like Student, an object name like stud, and use a new keyword. 

Student stud = new Student();

Let us create a class and an object of its class and print the value of the variable name.

public class Student {

    String Name = "Tom";
    public static void main(String[] args)

    {
        Student stud = new Student();
        System.out.println("Name of Student :"+stud.Name);
    }
}

Multiple Objects of a Class

We can create multiple objects of a class. In the below example, we have created 2 objects of class Student.

public class Student {

    String Name = "Tom";
    public static void main(String[] args)
    {
        Student stud1 = new Student();
        Student stud2 = new Student();
        System.out.println("Name of Student :"+stud1.Name);
        System.out.println("Name of Student :"+stud2.Name);
    }
}

Multiple Classes

We can create a class and then create an object of that class in another class. Like, here, we have created a class called Student.java and another class is Student_Demo.java where we will create the object of class Student. This is a better approach than the previous one.

public class Student {
          String Name = "Tom";         
}


public class Student_Test{
    public static void main(String[] args)
    {
        Student stud = new Student();
        System.out.println("Name of Student :"+stud.Name);
    }
}

There are multiple ways to initialize the classes and objects.

1) Initialize through reference

Here, initializing an object means storing data in the object. Let’s see a simple example where we are going to initialize the object through a reference variable.

public class Student {
          String Name ;
          int Age;
}

public class Student_Test {
    public static void main(String[] args)
    {
        Student stud = new Student();
        stud.Name ="Tom";
        stud.Age=35;
        System.out.println("Name of Student :"+stud.Name);
        System.out.println("Age of Student :"+stud.Age);
    }
}

2) Initializing through method

We are creating the two objects of the Student class and initializing the value to these objects by invoking the InsertData() method. Here, we are displaying the state (data) of the objects by invoking the DisplayData() method.

public class Student {
	String Name;
	int Age;

	void InsertData(String n, int a) {
		Name = n;
		Age = a;
	}

	void DisplayData() {
		System.out.println("Name of Student :" + Name);
		System.out.println("Age of Student :" + Age);
	}
}


public class Student_Test {
    
    public static void main(String[] args) {
        Student stud = new Student();
        stud.InsertData("Tom", 34);
        stud.DisplayData();
    }
}

We can create multiple objects

public class Student {
          String Name ;
          int Age;

          void InsertData(String n, int a)
          {
                   Name =n;
                   Age = a;
          }

          void DisplayData()
          {
                   System.out.println("Name of Student :"+Name);
                   System.out.println("Age of Student :"+Age);
          }
    }  


public class Student_Test {
    
    public static void main(String[] args) {

            Student stud1 = new Student();
            Student stud2 = new Student();
            stud1.InsertData("Matt",43);
            stud1.DisplayData();
            stud2.InsertData("Terry",36);
            stud2.DisplayData();
    }
 }

Method Overloading in Java

HOME

public class MethodOverloading_Demo {

    public void Calculation(int a, float b) {
        System.out.println("Sum of 2 numbers :" + (a + b));
    }

    //Different type of parameters
    public void Calculation(float x, float y) {
        System.out.println("Sum of 2 numbers :" + (x + y));
    }

    //Different number of parameters
    public void Calculation(int i, int j, int k) {
        System.out.println("Sum of 3 numbers :" + (i + j + k));
    }

    //Different sequence of parameters
    public void Calculation(float p, int r) {
        System.out.println("Sum of 3 numbers :" + (p + r));
    }

    public static void main(String[] args) {

        MethodOverloading_Demo add = new MethodOverloading_Demo();

        //Call overloaded methods
        add.Calculation(5, 12f);
        add.Calculation(13f, 12.0f);
        add.Calculation(22, 33, 50);
        add.Calculation(11f, 10);
    }

}

What is Type Promotion?

When a data type of smaller type, promote to bigger type, it called type promotion.  Suppose a method has double data type and object provides float, then the program works fine. Float will be promote to double.

Let us explain this with an example. In the below example, object has provided float data type, but method has double data type, so there is type promotion.

public class Addition {

    public void Calculation(int a, int b)  {
        System.out.println("Sum of 2 numbers :"+(a+b));
    }

    public void Calculation(int x, double y)   {
        System.out.println("Sum of 2 numbers :"+(x+y));
    }

    public static void main(String[] args) {
        Addition add = new Addition();
        //Type Promotion method
        add.Calculation(5,12);
        add.Calculation(13,12f);
    }
}

How to verify the response time of a request in Rest Assured?

HOME

import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.junit.Test;
import java.util.concurrent.TimeUnit;

public class ResponseTime {


    @Test
    public void getResponseTime() {

        RequestSpecification  requestSpecification = RestAssured.given();

        // Calling GET method
        Response response = requestSpecification.get("https://reqres.in/api/users/2");

        // Let's print response body.
        String resString = response.prettyPrint();
        System.out.println("Response Details : " + resString);

        //Get Response Time
        System.out.println("Response Time in milliseconds: " + response.getTime());

        System.out.println("Response Time in seconds: " + response.getTimeIn(TimeUnit.SECONDS));

        System.out.println("Response Time in milliseconds: " + response.time());

        System.out.println("Response Time in seconds: " + response.timeIn(TimeUnit.SECONDS));

    }

    }

import org.hamcrest.Matchers;
import org.junit.Test;
import static io.restassured.RestAssured.given;

public class ResponseTime {

    @Test
    public void verifyResponseTime() {

        // Given
        given()

                // When
                .when()
                .get("https://reqres.in/api/users/2")

                // Then
                .then()
                .statusCode(200).statusLine("HTTP/1.1 200 OK")

                // Asserting response time is less than 2000 milliseconds
                .time(Matchers.lessThan(3000L));

    }
}

    @Test
    public void verifyGreaterResponseTime() {

        // Given
        given()

                // When
                .when()
                .get("https://reqres.in/api/users/2")

                // Then
                .then()
                .statusCode(200).statusLine("HTTP/1.1 200 OK")

                // Asserting response time is greater than 3000 milliseconds
                .time(Matchers.greaterThan(2000L));
    }

    @Test
    public void verifyResponseTimeRange() {

        // Given
        given()

                // When
                .when()
                .get("https://reqres.in/api/users/2")

                // Then
                .then()
                .statusCode(200).statusLine("HTTP/1.1 200 OK")

                // Asserting response time is greater than 1000 milliseconds and less than 2000 milliseconds
                .time(Matchers.both(Matchers.greaterThanOrEqualTo(1000L)).and(Matchers.lessThanOrEqualTo(2000L)));
    }

Marshalling- How to convert Java Objects to XML using JAXB

HOME

This tutorial explains how to use JAXB (Java Architecture for XML Binding) to convert Java Objects to XML documents.

JAXB provides a fast and convenient way to marshal (write) Java Objects into XML and un-marshal (read) XML into Java Objects. It supports a binding framework that maps XML elements and attributes to Java fields and properties using Java annotations.

With Java releases lower than Java 11, JAXB was part of the JVM and you could use it directly without defining additional libraries.

As of Java 11, JAXB is not part of the JRE anymore, and you need to configure the relevant libraries via your dependency management system, for example, either Maven or Gradle.

Configure the Java compiler level to be at least 11 and add the JAXB dependencies to your pom file.

<?xml version="1.0" encoding="UTF-8"?>

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

  <groupId>org.example</groupId>
  <artifactId>JAXBDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>JAXBDemo</name>
  <url>http://www.example.com</url>

  <properties>  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <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>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
  </dependency>
    
 <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>4.0.4</version>
   </dependency>
 </dependencies>
   
<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </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>
    </plugins>
  </build>
</project>

JAXB Annotations

  1. @XmlRootElement: Define the root element for an XML tree
  2. @XmlType: Define the order in which the fields are written in the XML file
  3. @XmlElement: Define the actual XML element name which will be used
  4. @XmlAttribute: Define the id field is mapped as an attribute instead of an element
  5. @XmlTransient: Annotate fields that we don’t want to be included in XML

Sample XML Structure

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EmployeeDetails>
    <firstName>Vibha</firstName>
    <lastName>Singh</lastName>
    <gender>female</gender>
    <age>30</age>
    <maritalStatus>married</maritalStatus>
    <designation>Manager</designation>
    <contactNumber>+919999988822</contactNumber>
    <emailId>abc@test.com</emailId>
    <GrossSalary>75000.0</GrossSalary>
</EmployeeDetails>

Marshalling

Marshalling provides a client application the ability to convert a JAXB derived Java object tree into XML data.

Let’s see the steps to convert Java Objects into XML document.

  1. Create POJO Class of XML
  2. Create the JAXBContext object
  3. Create the Marshaller objects
  4. Create the content tree by using set methods
  5. Call the marshal method

Now, let us create the Java Objects (POJO).

import jakarta.xml.bind.annotation.*;

@XmlRootElement(name = "EmployeeDetails")
@XmlAccessorType(XmlAccessType.FIELD)

//Define the order in which the fields are written in XML
@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber",
		"emailId", "salary" })

public class Employee {

	private String firstName;
	private String lastName;
	private int age;

    @XmlElement(name = "GrossSalary")
	private double salary;
	private String designation;
	private String contactNumber;
	private String emailId;
	private String gender;
	private String maritalStatus;

	// Getter and setter methods
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public String getDesignation() {
		return designation;
	}

	public void setDesignation(String designation) {
		this.designation = designation;
	}

	public String getContactNumber() {
		return contactNumber;
	}

	public void setContactNumber(String contactNumber) {
		this.contactNumber = contactNumber;
	}

	public String getEmailId() {
		return emailId;
	}

	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public String getMaritalStatus() {
		return maritalStatus;
	}

	public void setMaritalStatus(String maritalStatus) {
		this.maritalStatus = maritalStatus;
	}

   @Override
	public String toString() {
		return "Employee [FirstName=" + firstName + ", LastName=" + lastName + ", Age=" + age + ", Salary=" + salary
				+ ", Designation=" + designation + ", ContactNumber=" + contactNumber + ", EmailId=" + emailId
				+ ", Gender=" + gender + ", MaritalStatus=" + maritalStatus + "]";
	}
}

Create the following test program for writing the XML file.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import org.junit.Test;
import java.io.StringWriter;

public class SerializationDemo {

    @Test
    public void serializationTest1() {

        try {

            Employee employee = new Employee();

            employee.setFirstName("Terry");
            employee.setLastName("Mathew");
            employee.setAge(30);
            employee.setSalary(75000);
            employee.setDesignation("Manager");
            employee.setContactNumber("+919999988822");
            employee.setEmailId("abc@test.com");
            employee.setMaritalStatus("married");
            employee.setGender("female");

            // Create JAXB Context
            JAXBContext context = JAXBContext.newInstance(Employee.class);

            // Create Marshaller
            Marshaller jaxbMarshaller = context.createMarshaller();

            // Required formatting
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            // Write XML to StringWriter
            StringWriter sw = new StringWriter();
            jaxbMarshaller.marshal(employee, sw);

            // Convert XML to String
            String xmlContent = sw.toString();
            System.out.println(xmlContent);

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

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

When we run the code above, we may check the console output to verify that we have successfully converted Java object to XML:

By default, the Marshaller uses UTF-8 encoding when generating XML data.

The javax.xml.bind.JAXBContext class provides a client’s entry point to JAXB API. By default, JAXB does not format the XML document. This saves space and prevents that any white-space may accidentally be interpreted as significant.

To have JAXB format the output, we simply set the Marshaller.JAXB_FORMATTED_OUTPUT property to true on the Marshaller. The marshal method uses an object and an output file where to store the generated XML as parameters.

You can see that we have used JAXB Annotations like @XMLRootElement are changed from Employee to EmployeeDetails.

The order of elements in the XML is defined by

@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber","emailId", "salary" })

@XMLElement has set the element name to GrossSalary from Salary.

The below example is the short way of writing the same test and saving XML. We need to add a constructor in the POJO class so that we can set the values to the variables through the Constructor.

import jakarta.xml.bind.annotation.*;

@XmlRootElement(name = "EmployeeDetails")
@XmlAccessorType(XmlAccessType.FIELD)

//Define the order in which the fields are written in XML
@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber",
        "emailId", "salary" })

public class Employee {

    private String firstName;
    private String lastName;
    private int age;

    @XmlElement(name = "GrossSalary")
    private double salary;
    private String designation;
    private String contactNumber;
    private String emailId;
    private String gender;
    private String maritalStatus;

    public Employee() {
        super();

    }

    public Employee(String firstName, String lastName, int age, double salary, String designation, String contactNumber,
                    String emailId, String gender, String maritalStatus) {

        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;


        this.salary = salary;

        this.designation = designation;
        this.contactNumber = contactNumber;
        this.emailId = emailId;
        this.gender = gender;
        this.maritalStatus = maritalStatus;
    }

    // Getter and setter methods
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public String getContactNumber() {
        return contactNumber;
    }

    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getMaritalStatus() {
        return maritalStatus;
    }

    public void setMaritalStatus(String maritalStatus) {
        this.maritalStatus = maritalStatus;
    }

    @Override
    public String toString() {
        return "Employee [FirstName=" + firstName + ", LastName=" + lastName + ", Age=" + age + ", Salary=" + salary
                + ", Designation=" + designation + ", ContactNumber=" + contactNumber + ", EmailId=" + emailId
                + ", Gender=" + gender + ", MaritalStatus=" + maritalStatus + "]";
    }
}

The below JAXB example for XML marshalling convert Java objects into an XML.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import org.junit.Test;
import java.io.File;
import java.io.StringWriter;

public class SerializationDemo {


    @Test
    public void serializationTest2() {

        try {

            Employee employee = new Employee("Thomas", "Pawsey", 35, 100000, "Director", "+919999988822","Test@test.com", "married", "female");

            // Create JAXB Context
            JAXBContext context = JAXBContext.newInstance(Employee.class);

            // Create Marshaller
            Marshaller jaxbMarshaller = context.createMarshaller();

            // Required formatting
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            // Write XML to StringWriter
            StringWriter writer = new StringWriter();
            jaxbMarshaller.marshal(employee, writer);

            // Convert XML to String
            String xmlContent = writer.toString();
            System.out.println(xmlContent);

            // Save the file
            String userDir = System.getProperty("user.dir");
            jaxbMarshaller.marshal(employee, new File(userDir + "\\src\\test\\resources\\JAXB_XML.xml"));
            System.out.println("File is saved");
            
        } catch (PropertyException e) {
            e.printStackTrace();

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

When we run the code above, we may check the console output to verify that we have successfully converted Java object to XML:

The XML is saved under src/test/resources. To see this file, after the execution of the test, you need to refresh the project.

Similarly, we can unmarshal an XML to Java Objects in the next tutorial.

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

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

HOME

 <!-- Log4j Dependency -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>3.0.0-alpha1</version>
    </dependency>

<!-- Jackson Dataformat YAML -->
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-yaml</artifactId>
      <version>2.16.0</version>
    </dependency>

<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>
    <jackson.version>2.16.0</jackson.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>

    <!-- Jackson Dataformat YAML -->
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-yaml</artifactId>
      <version>${jackson.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>

Configuration:
  status: warn

  appenders:
    Console:
      name: LogToConsole
      PatternLayout:
        Pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"

    File:
      name: File
      fileName: logs/app.log
      PatternLayout:
      Pattern: "%d %p %C{1.} [%t] %m%n"


  Loggers:
    logger:
      - name: com.example
        level: debug
        additivity: false
        AppenderRef:
          - ref: LogToConsole
          - ref: File

    Root:
      level: error
      AppenderRef:
        ref: LogToConsole

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");
    By actualErrorMessage =  By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p");

    // 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"));

    }

    @Test(description = "This test validates unsuccessful login", priority = 2)
    public void verifyIncorrectCredentials() {

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

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

        driver.findElement(loginBtn).submit();
        logger.info("Error Message is displayed");
        String ErrorMessage = driver.findElement(actualErrorMessage).getText();

        logger.info("Error Message :" + ErrorMessage);
        Assert.assertEquals(ErrorMessage, "Invalid credentials");
    }

    @AfterMethod
    public void teardown() {

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

}

If you want to add RollingFile details in the file, you can refer to the below file for the same.

    RollingFile:
      - name: LogToRollingFile
        fileName: logs/app.log
        filePattern: "logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"
        PatternLayout:
          pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"
        Policies:
          SizeBasedTriggeringPolicy:
            size: 1KB
        DefaultRollOverStrategy:
          max: 5

Jackson Annotations for XML – JacksonXmlRootElement

HOME

The Jackson XML module adds some additional support for XML-specific features, just like JSON has some additional features. These annotations allow us to control the XML namespace and local name for elements, including the root element, whether a field is rendered in an element or as plain text, whether the content of an element is rendered in a CData wrapper, and whether a collection should use a wrapper element or not.

We need to add Jackson XML dependency to the project.

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

It is used to define the name of the root element used for the root-level object when serialized, which normally uses the name of the type (class). This can only adjust the Namespace and Local name – since the root element can never be serialized as an attribute.

@JacksonXmlRootElement(localName = "Employee_Details")

Below is the example of JacksonXmlRootElement.

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

@JacksonXmlRootElement(localName = "Employee_Details")
public class Employee {

    // Data members of POJO class
    private String firstName;
    private String lastName;
    private int age;
    private double salary;
    private String designation;
    private String contactNumber;
    private String emailId;
    private String gender;
    private String maritalStatus;

    // Getter and setter methods
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public String getContactNumber() {
        return contactNumber;
    }

    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getMaritalStatus() {
        return maritalStatus;
    }

    public void setMaritalStatus(String maritalStatus) {
        this.maritalStatus = maritalStatus;
    }

}

Let us create a test to build an XML.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.junit.Test;

public class EmployeeXMLTest {

    @Test
    public void serializationTest() {

        // Create an object of POJO class
        Employee employee = new Employee();

        employee.setFirstName("Vibha");
        employee.setLastName("Singh");
        employee.setAge(35);
        employee.setSalary(135000);
        employee.setDesignation("Manager");
        employee.setContactNumber("+919999988822");
        employee.setEmailId("abc@test.com");
        employee.setMaritalStatus("married");
        employee.setGender("female");

        // Converting a Java class object to XML
        XmlMapper xmlMapper = new XmlMapper();

        try {
            String employeeXml = xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee);
            System.out.println(employeeXml);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }
}

The output of the above program is

You can see here that localName of XML is Employee_Details, not Employee.

@JacksonXmlRootElement(namespace = "urn:request:jacksonxml", localName = "Employee_Details")

The XML is shown below.

Hope this helps to understand @JacksonXmlRootElement.

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