How to take ScreenShot of failed test case using ITestListener Interface?

Taking Screen shot of all the test cases may create a memory issue, because we will be running the automation suite multiple times. Moreover, we can see the status of test cases (pass / failed / skipped) in the testing report. 
So, what is better is, to take the screen shot of only failed test cases.
To achieve this, we need to trigger an event (of capturing screen shot) whenever any test case fails. We can use testng listener for this purpose.
Let us see how can we use ITestListener
 
Basically, ITestListener is an interface, which we need to implement in our class.
Follow these steps to take screen shot of failed test cases only.
          1.      Create sample class & implement ITestListener
          2.      Write code to capture screen shot in OnTestFailure Method.
v        3.      Define listener either in testng.xml (if you want to apply this for all the classes which are going to execute from testng.xml) or in the class which contains testng tests( if you want to apply this to only some specific class)
          4.      That’s it, all done. Refer below code & screenshots.
Create a sample class and implements ITestListener in it.
When you import ITestListener in the class, you will see option to implement unimplemented methods.
Refer below screen shot.

Once clicked on “Add unimplemented methods”, all methods will be implemented, code will look like –

package screenshotOfFailedTest;

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

public class ListenerClass implements ITestListener {

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

}

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

}

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

}

@Override
public void onTestFailure(ITestResult arg0) {
// TODO Auto-generated method stub

}

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

}

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

}

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

}

}
In the above code, ITestResult is an interface which keeps all information about test case which is being executed. It captures some information like Test case execution status, test case name etc.
Now, if you want to capture screen shot of only failed test cases, then you need to write the code to capture screen shot in OnTestFailure method.

Note:
To take screen shot in selenium, we have one predefined interface known as TakesScreenshot, we can not create object of an interface in java. So we need to typecast it to Webdriver object.
                TakesScreenshot ts = (TakesScreenshot)driver;       (can’t create object directly so typecast and then create ).
                File srcFile = ts.getScreenShotAs(OutPutType.FILE);              (use the object created, then get screenshot as file & assign it to the File variable).
           FileUtils.copyFile(srcFile, new File(“./ScreenShots/image1.png”);        (now you need to copy the srcFile, so use FileUtils class, then give source file & destination file. In destination file “.” (dot) refers to the current working directory)     
                            
Refer below code now –
First Create one sample test case,
package screenshotOfFailedTest;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;


@Listeners (screenshotOfFailedTest.ListenerClass.class)

public class SampleTest {

public static WebDriver driver;

@Test
public void TestCase(){
driver = new FirefoxDriver();
driver.navigate().to("https://learnaboutsoftwaretesting.blogspot.in/");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();

driver.findElement(By.xpath("invalidXpath")).click(); //using invalid xpath so that test will fail & we can invoke ITestListener.
}

}
Note: We need to mention somewhere about listenerclass in our test case. There are 2 ways to do so. You may like to do this at class level (this will be applicable to all test cases in that class) or you may like to do this at suite level (which will be applicable to whole suite. You need to define this in testng.xml file).
In above example. I have done it for class level by adding below line of code for listener.
                              @Listeners(screenshotOfFailedTest.ListenerClass.class)
Now, Update the above created listener class for onTestFailure method. Add the code to take screen shot in this method. The code will look like –

package screenshotOfFailedTest;

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

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class ListenerClass implements ITestListener {
CaptureScreenShot c = new CaptureScreenShot();

@Override
public void onFinish(ITestContext arg0) { }

@Override
public void onStart(ITestContext arg0) { }

@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult arg0) { }

@Override
public void onTestSkipped(ITestResult arg0) { }

@Override
public void onTestStart(ITestResult arg0) { }

@Override
public void onTestSuccess(ITestResult arg0) { }

@Override
public void onTestFailure(ITestResult arg0) {

//in below code, "SampleTest.driver" is used to get same driver from sample test class.
TakesScreenshot ts = (TakesScreenshot)SampleTest.driver;

File srcFile = ts.getScreenshotAs(OutputType.FILE);

try {
FileUtils.copyFile(srcFile, new File("./ScreenShots/"+arg0.getName()+".jpg"));
} catch (IOException e) {
e.printStackTrace();
}

}
}
This is all done. Now whenever you run the test case & if it fails, the screenshot will be captured at given location.

Hope this helps !!!!

2 Comments

  1. kwood

    Reply

    You have ‘SampleTest.driver’ hard coded in your listener. How do we get the webdriver when we don’t already know the name of the test class?

    • Prakash Narkhede

      Reply

      Hello,

      You need to use ITestResult interface to achieve this.

      Refer below teardown method,–> to this method i am passing parameter called ITestResult.

      public void teadDown(ITestResult result) throws IOException {
      if(result.getStatus() == ITestResult.FAILURE) {
      logger.log(Status.FAIL, MarkupHelper.createLabel(result.getName() + “Test Case Failed.”, ExtentColor.RED));
      logger.log(Status.FAIL, MarkupHelper.createLabel(result.getThrowable() + “Test Case Failed.”, ExtentColor.RED));

      String screenShotName = result.getMethod().getMethodName().toString();
      String screenshotPath = cm.captureScreenShot(screenShotName);

      logger.fail(“Test Case is failed, Screenshot is attached. “+logger.addScreenCaptureFromPath(screenshotPath));

      //take screenshot
      //add it in report
      //report failure message
      }
      if(result.getStatus() == ITestResult.SKIP) {
      //report skip message in execution report
      logger.log(Status.SKIP, MarkupHelper.createLabel(result.getName()+ “- Test Case is SKipped.”, ExtentColor.ORANGE));
      }
      if(result.getStatus() == ITestResult.SUCCESS) {
      //report success message in execution report
      logger.log(Status.PASS, MarkupHelper.createLabel(result.getName()+ “- Test Case is Passed.”, ExtentColor.GREEN));
      }

      //how to get status?

      //take screenshot of failed test
      //add entry in extent report
      // close browser

      driver.close();

      }

Leave Comment

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

Looking for learning Framework Development from Scratch? Lookout for Detailed Framework Development videos on YouTube here -

https://www.youtube.com/automationtalks

Get the Framework code at Github Repo: https://github.com/prakashnarkhede?tab=repositories