Take Screenshot Of Failed Test Cases Using Selenium

Screenshot Failed Test Case

Screenshots play a vital role in testing. These can be used as evidence for functionality under test, raising a defect or for asking a query etc. During automation, regression suite is usually executed in a remote machine or during off-hours. Automation testers cannot keep an eye on every step during execution, and screenshots help them to quickly identify problem areas without juggling through the logs.

We can take screenshot of failed test cases using selenium, which is generally required (we can also take screenshot for other test statuses). We will use ITestListener interface of TestNG to track which steps get fail and take their screenshot.

TestNG Listeners In Selenium

Click Here

Listener Used For Taking Screenshot

We have already learned about various listeners in TestNG and ITestListener is the interface which contains methods for each test status. One of the methods in ITestListener interface is onTestFailure() which will be used to take screenshot of failed test cases in selenium. ITestListener is invoked whenever there is a change in test status.

See All The Methods Of ITestListener Interface

click Here

Main Components For Taking Screenshot

Following components are the basic requirement to take screenshot of failed test cases using selenium:

  • BaseClass is the main or parent class. This class contains the @Before and @After annotations  along with other configurations (setup driver instance, invoke browser, set driver wait time etc.)
  • FirstTest is the test script name to be automated.
  • ScreenShotListener class implements the ITestListener interface. In this class, we will override the onTestFailure() method with the code to take a screenshot whenever a test fails.
  • TestUtil class contains the code to take the screenshot, name the screenshot file and save it in a specified path.
  • testng_failscreenshot.xml to drive the test execution.
Screenshot implementation
ITestListener Implementation to Take Screenshot Of Failed Test Cases Using Selenium

Above figure describes the relationship which is used to implement code to take screenshot of failed test cases using selenium. 

Code to take screenshot of failed test cases using selenium

We will start writing our code to implement the screenshot functionality, but before directly jumping into Eclipse IDE and start coding, let’s assume:

  • We will write 2 test cases (scripts/ methods) in a single test class (FirstTest.java).
  • First Test script would be to open the browser, navigate to https://www.google.com/, enter some text and click on Google Search button.
  • The second test would only contain one line of code Assert.fail(), to fail the test case deliberately.

Create a project in Selenium, create a package onTestFailScreenShot and create the following classes (visit below if you have not already gone through the tutorial to work with TestNG):

What is TestNG and How to use TestNG in Selenium | TestNG Selenium Tutorial

click Here

BaseClass.java

This is the parent class which will contain @BeforeSuite and @AfterSuite annotations. These annotations are used as we are going to launch the browser only once for this test class. 

We will also define our WebDriver and ChromeDriver instances in this class. You may also define default wait times and other configuration tasks in this class.

package onTestFailScreenShot;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;

public class BaseClass {
    public static WebDriver driver;
    
    //Browser should only opened once during whole test execution
    @BeforeSuite
    public void setUp() {
        System.setProperty("webdriver.chrome.driver", "/home/dhawal/Downloads/chromedriver/chromedriver");
        driver = new ChromeDriver();
        driver.get("https://www.google.com/");
        driver.manage().window().maximize();
        
    }
    
    //Browser will be closed after all the methods in FirstTest are finished execution
    @AfterSuite
    public void tearDown() {
        driver.quit();
    }

}

FirstTest.java

This class contains the following 2 methods (tests).  It also extends BaseClass as WebDriver and other configurations are set up in BaseClass.

package onTestFailScreenShot;

import org.openqa.selenium.By;
import org.testng.Assert;
import org.testng.annotations.Test;

public class FirstTest extends BaseClass{
    
    //Enter some text and click on Search button
    @Test
    public void search() {
        driver.findElement(By.name("q")).sendKeys("Applied Selenium");
        driver.findElement(By.xpath("//div[@class='FPdoLc VlcLAe']//input[@value='Google Search']")).click();
    }
    
    
    //Deliberately fail the test case
    @Test
    public void feelingLucky() {
        Assert.fail();
    }

}

ScreenShotListener.java

This class also extends BaseClass and implements ITestListener interface from TestNG. Write below code and press CTL+SHIFT+O to implement all the overridden methods from this interface. The code should look like below:

package onTestFailScreenShot;

import java.io.IOException;

import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class ScreenShotListener extends BaseClass implements ITestListener {

    @Override
    public void onTestStart(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTestSuccess(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    //Override below method to implement screenshot
    @Override
    public void onTestFailure(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTestSkipped(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onStart(ITestContext context) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onFinish(ITestContext context) {
        // TODO Auto-generated method stub
        
    }

}

We need not to write code for all the methods. Since we are interested in taking the screenshot when a test fails, overriding of onTestFailure() method is sufficient. We will revisit this class once we implement the logic to take the screenshot in TestUtil class.

TestUtil.java

This class takes care of the following:

  • Create a unique file name for each screenshot by manipulating time/year/month etc using GregorianCalendar class.
  • Take screenshot and store it in a File reference variable after casting the variable to TakesScreenshot object.
  • Copy this reference to the unique path created in the first step.

You may save below code somewhere as this is the standard utility file which is created only once and you may only be required to change few things to get it working with any project.

package onTestFailScreenShot;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.io.FileHandler;

public class TestUtil extends BaseClass {

    public static String screenshotpath;

    public static void captureScreenshot(String methodName) throws IOException {

        //Using GregorianCalendar to fetch the time details
        Calendar cal = new GregorianCalendar();
        //Month value is always 1 less than actual. For February, MONTH would return 1 
        int month = cal.get(Calendar.MONTH);
        int year = cal.get(Calendar.YEAR);
        int sec = cal.get(Calendar.SECOND);
        int min = cal.get(Calendar.MINUTE);
        int date = cal.get(Calendar.DATE);
        int day = cal.get(Calendar.HOUR_OF_DAY);

        //Take screen shot and store it in volatile memory with reference name scrFile
        File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        try {

            //Create unique file name and store in under screenshot folder of root directory
            screenshotpath = System.getProperty("user.dir") + "/screenshot/" + methodName + "_" + year + "_" + date+ "_" + (month + 1) + "_" + day + "_" + min + "_" + sec + ".jpeg";
            
            //Copy the file to destination
            FileHandler.copy(scrFile, new File(screenshotpath));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();

        }

    }

}

Create a folder screenshot at the root of your project folder if selenium fails to create it at run time

Method captureScreenshot have one parameter methodName which is the name of the test in class FirstTest.java. If there are multiple test methods in a Test class (or if there are multiple test classes containing multiple test methods), then the screenshot file name would contain this method name which will help in identifying the test case.

ScreenShotListener.java (Updated)

The updated code is highlighted in bold below:

package onTestFailScreenShot;

import java.io.IOException;

import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class ScreenShotListener extends BaseClass implements ITestListener {

    @Override
    public void onTestStart(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTestSuccess(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    //Override below method to implement screenshot
    @Override
    public void onTestFailure(ITestResult result) {
        try {
            TestUtil.captureScreenshot(result.getName().toString());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    @Override
    public void onTestSkipped(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onStart(ITestContext context) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onFinish(ITestContext context) {
        // TODO Auto-generated method stub
        
    }

}

In our previous tutorial, we have already learned what is ITestResult and result. the result contains the information regarding the test status and result.getName() will fetch the failed test case name. Use toString() method to convert it into a string variable.

This method will automatically execute whenever a test status is changed to fail.

testng_failscreenshot.xml

Follow THIS tutorial to learn how to implement listeners in testng.xml.

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Fail Screenshot">

<listeners>
        <listener class-name="onTestFailScreenShot.ScreenShotListener" />
    </listeners>

    <test name="fail_screenshot">
        <classes>
            <class name="onTestFailScreenShot.FirstTest">

            </class>
        </classes>
    </test>

</suite>

If you execute the above XML, test feelingLucky() would get failed. Since we are doing anything in this test, let’s change locator to some invalid value for search() test case.

driver.findElement(By.name("q1")).sendKeys("Applied Selenium");

Execute the XML now, the test would get failed. Refresh your project and you should see a folder screenshot. This folder would contain the screenshot of the failed test case.

Below is the screenshot after executing the above test.

Failed Test Step Screenshot

Author: Dhawal Joshi

A post-graduate in MCA, ISTQB & ITIL certified QA with more than 8 years of experience in QA working with a CMMI Level 5 organization as System Analyst. I started my automation journey with HP UFT(formerly known as QTP) and for the past few years, I am using Selenium for automation. I also have experience in Android Application Development, Java, HTML, and VBScript. When I am not working, I like to spend time with my family, cooking and learning new developments in IT.

1 thought on “Take Screenshot Of Failed Test Cases Using Selenium

Leave a Reply

Your email address will not be published. Required fields are marked *