Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Creating Extent Reports in Selenium Using the Extent API

DZone's Guide to

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.

· DevOps Zone ·
Free Resource

Easily enforce open source policies in real time and reduce MTTRs from six weeks to six seconds with the Sonatype Nexus Platform. See for yourself - Free Vulnerability Scanner. 

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

Automate open source governance at scale across the entire software supply chain with the Nexus Platform. Learn more.

Topics:
selenium 3.0 ,selenium ,testng ,unit testing ,devops ,software testing

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}