DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Day in the Life of a Developer With Google’s Gemini Code Assist: Part 1
  • That Can Not Be Tested!: Spring Cache and Retry
  • Supercharging Productivity in Microservice Development With AI Tools
  • Improving Customer-Facing App Quality Using Tricentis Testim

Trending

  • Testing Java Applications With WireMock and Spring Boot
  • Breaking Free from ZooKeeper: Why Kafka’s KRaft Mode Matters
  • A Keycloak Example: Building My First MCP Server Tools With Quarkus
  • The Death of REST? Why gRPC and GraphQL Are Taking Over
  1. DZone
  2. Data Engineering
  3. Databases
  4. Creating Extent Reports in Selenium Using the Extent API

Creating Extent Reports in Selenium Using the Extent API

Learn how to implement the Extent API in Selenium using TestNG to create more interactive reports, a dashboard view, emailable reports, and more.

By 
Aswani Kumar Avilala user avatar
Aswani Kumar Avilala
DZone Core CORE ·
Feb. 27, 18 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
58.3K Views

Join the DZone community and get the full member experience.

Join For Free

The Extent API can produce more interactive reports, a dashboard view, graphical view, capture screenshots as images in the reports, and emailable reports which can be mailed right after the unit test is completed.

The Extent API can be configured to support programming languages like Java and .Net and unit testing frameworks like JUnit, TestNG, NUnit, etc.

Implementation of Extent API in Selenium Using TestNG 

To create reports with the Extent API, we need to follow the below steps.

Create a Maven project in Eclipse and add artifacts like Selenium, TestNG, and the Extent API as dependencies in the pom.xml, as shown below:

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.selenium</groupId>
<artifactId>PageObjectModel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.8.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.relevantcodes/extentreports -->
<dependency>
<groupId>com.relevantcodes</groupId>
<artifactId>extentreports</artifactId>
<version>2.41.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>

Create a listener class using ITestListener to capture the log messages in the Extent Reports when a test event occurs, as shown below. The Extent API uses the ExtentReports and ExtentTest class to generate reports

  • The ExtentReports object is used to generate an HTML report in the specified location. The path of the report is given as an argument in the ExtentReports constructor.

  • ExtentTest is initialized from the ExtentReports object by calling the lifecycle methods of reports. To start the log information in the reports, call startTest(). The return of startTest() is assigned to the test as a reference variable to ExtentTest.

  • The LogStatus enum is used to add the status message based on the test execution. We have constant values in LogStatus like INFO, PASS, FAIL, SKIP, ERROR, FATAL, WARNING, and UNKNOWN. Call the status message in the respective lifecycle method to get the appropriate message in the report.

  • End the test reports by calling endTest() and flush() from the reports to properly close the resources.

/**
 * @author aswani.kumar.avilala
 */
package com.listeners;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import com.relevantcodes.extentreports.ExtentReports;
import com.relevantcodes.extentreports.ExtentTest;
import com.relevantcodes.extentreports.LogStatus;

public class MyListener implements ITestListener {

 protected static WebDriver driver;
 protected static ExtentReports reports;
 protected static ExtentTest test;

 public void onTestStart(ITestResult result) {
  System.out.println("on test start");
  test = reports.startTest(result.getMethod().getMethodName());
  test.log(LogStatus.INFO, result.getMethod().getMethodName() + "test is started");
 }
 public void onTestSuccess(ITestResult result) {
  System.out.println("on test success");
  test.log(LogStatus.PASS, result.getMethod().getMethodName() + "test is passed");
 }
 public void onTestFailure(ITestResult result) {
  System.out.println("on test failure");
  test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test is failed");
  TakesScreenshot ts = (TakesScreenshot) driver;
  File src = ts.getScreenshotAs(OutputType.FILE);
  try {
   FileUtils.copyFile(src, new File("C:\\images\\" + result.getMethod().getMethodName() + ".png"));
   String file = test.addScreenCapture("C:\\images\\" + result.getMethod().getMethodName() + ".png");
   test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test is failed", file);
   test.log(LogStatus.FAIL, result.getMethod().getMethodName() + "test is failed", result.getThrowable().getMessage());
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 public void onTestSkipped(ITestResult result) {
  System.out.println("on test skipped");
  test.log(LogStatus.SKIP, result.getMethod().getMethodName() + "test is skipped");
 }
 public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
  System.out.println("on test sucess within percentage");
 }
 public void onStart(ITestContext context) {
  System.out.println("on start");
  driver = new ChromeDriver(); // Set the drivers path in environment variables to avoid code(System.setProperty())
  reports = new ExtentReports(new SimpleDateFormat("yyyy-MM-dd hh-mm-ss-ms").format(new Date()) + "reports.html");
 }
 public void onFinish(ITestContext context) {
  System.out.println("on finish");
  driver.close();
  reports.endTest(test);
  reports.flush();
 }

}


Design a Register Page using the Page Object Model design pattern, as shown below:    

/**
 * @author aswani.kumar.avilala
 */
package com.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class MercuryToursRegisterPage {

 WebDriver driver;
 @FindBy(xpath = "//input[@name='email']") WebElement email;
 @FindBy(xpath = "//input[@name='password']") WebElement password;
 @FindBy(css = "input[name='confirmPassword']") WebElement confirmPassword;
 @FindBy(name = "register") WebElement register;
 @FindBy(linkText = "SIGN-OFF") WebElement signoff;

 public MercuryToursRegisterPage(WebDriver driver) {
  super();
  this.driver = driver;
 }
 public String clickUserInfo() {
  email.sendKeys("askmail29");
  password.sendKeys("askmail29");
  confirmPassword.sendKeys("askmail29");
  register.click();
  return driver.getTitle();
 }
 public void clickSignOff() {
  signoff.click();
 }


}

    

Design a Login Page using the Page Object Model as a design pattern, as shown below:

/**
 * @author aswani.kumar.avilala
 */
package com.pages;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;

public class MercuryToursLoginPage {

 WebDriver driver;
 @FindBy(name = "userName") WebElement username;
 @FindBy(how = How.NAME, using = "password") WebElement password;
 @FindBy(how = How.XPATH, using = "//input[@value='Login']") WebElement signin;
 @FindBy(linkText = "REGISTER") WebElement register;

 public MercuryToursLoginPage(WebDriver driver) {
  super();
  this.driver = driver;
 }
 public String clickLogin() {
  username.sendKeys("askmail29");
  password.sendKeys("askmail29");
  signin.click();
  return driver.getTitle();
 }
 public void clickRegister() {
  register.click();
 }
 public void loadWebPage(String url) {
  driver.get(url);
  driver.manage().window().maximize();
  driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
 }
}


Design a test class which contains the actual call to the object repository created in the Page       classes:

/**
 * @author aswani.kumar.avilala
 */
package com.tests;
import org.testng.annotations.Test;
import com.listeners.MyListener;
import com.pages.MercuryToursLoginPage;
import com.pages.MercuryToursRegisterPage;
import com.relevantcodes.extentreports.LogStatus;
import org.testng.annotations.BeforeTest;
import org.openqa.selenium.support.PageFactory;
import org.testng.Assert;
import org.testng.annotations.AfterTest;

public class TestApp extends MyListener {

 MercuryToursLoginPage mlp;
 MercuryToursRegisterPage mrp;

 @BeforeTest
 public void beforeTest(String browserName) {
  mlp = PageFactory.initElements(driver, MercuryToursLoginPage.class);
  mrp = PageFactory.initElements(driver, MercuryToursRegisterPage.class);
 }
 @AfterTest
 public void afterTest() {
  System.out.println("in after test");
  mlp = null;
  mrp = null;
 }
 @Test
 public void testMercuryTours() {
  System.out.println("in test method");
  mlp.loadWebPage("http://newtours.demoaut.com");
  mlp.clickRegister();
  mrp.clickUserInfo();
  mrp.clickSignOff();
  String title = mlp.clickLogin();
  Assert.assertEquals(title, "Find a Flight: Mercury Tours:");
  test.log(LogStatus.INFO, "the test tours is passed");
 }

}


Configure the testng.xml file with listeners and the test classes. Attach the listener class to the test in the testng.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="tests">
<listeners>
<listener class-name="com.listeners.MyListener"></listener>
</listeners>
<test name="Test1">
<classes>
<class name="com.tests.TestApp" />
</classes>
</test>
</suite>
<!-- Suite -->


Execute the test as a suite, as shown below:

Image title

Reports are generated in the project structure with the file name as the SimpleDateFormat.html files.

When there is a failure in the test, the onTestFailure() lifecycle method is called from the listener class as it captures the screen and adds the captured image to the report, as shown below:Image title

When all the tests are passed, the report is shown, the onTestSuccess() lifecycle method is called from the listener class, and the respective report is generated, as shown below:

Image title

We can also view the reports in the form of a dashboard, as shown below:   

Image title

API Extent (file systems) unit test

Opinions expressed by DZone contributors are their own.

Related

  • Day in the Life of a Developer With Google’s Gemini Code Assist: Part 1
  • That Can Not Be Tested!: Spring Cache and Retry
  • Supercharging Productivity in Microservice Development With AI Tools
  • Improving Customer-Facing App Quality Using Tricentis Testim

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: