Logging using Listeners (ITestListener) in TestNG

Logging is very important in selenium framework, it helps us to understand the code, it helps a lot while debugging, and lot many other advantages.
For logging the message in selenium, we have multiple options. One way is to use Log4J API.
Refer below post to know how can we do logging using Log4j.
Another way to perform logging is, with the help of ITestListener interface of TestNG.
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.
Once we implement ITestListener interface, below methods are created –
onFinish -> you can write some message here which will be written in to log file after finishing execution.
onStart -> you can write some message here which will be written in to log file after execution starts.
onTestFailedButWithinSuccessPercentage -> written in to log file after test failed, but within success percentage.
onTestFailure -> you can write some message here which will be written in to log file if test fails.
onTestSkipped -> you can write some message here which will be written in to log file if test skips.
onTestSuccess -> you can write some message here which will be written in to log file after successful execution of test.
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.      After implementation, various methods are created. Put the proper message as required.
         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) {
// write the logging code here which will be executed on test finish
log("Test Finished....");

}

@Override
public void onStart(ITestContext arg0) {
// write the logging code here which will be executed on test start
log("Test Started....");

}

@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult arg0) {
// write the logging code here which will be executed on test failure within success %
log("Test failed but is within....");

}

@Override
public void onTestFailure(ITestResult arg0) {
// write the logging code here which will be executed on test failure
log("Test failed....");

}

@Override
public void onTestSkipped(ITestResult arg0) {
// write the logging code here which will be executed on test skip
log("Test Skipped....");

}

@Override
public void onTestStart(ITestResult arg0) {
// write the logging code here which will be executed on test start
log("Test Started....");

}

@Override
public void onTestSuccess(ITestResult arg0) {
// write the logging code here which will be executed on test success
log("Test completed successfully....");

}

}
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.
Note: Using ITestResult is variable, we can get various states / information about current test, which is under execution, like – arg0.getName(), arg0.getMethod().getPriority()
               
Refer below code in which we will use above defined Listener.

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.
}

}

So, in above program, test is failing, since listener is used there, onTestfailure() method will execute.
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)
Hope this helps !!!!!

How to take ScreenShot of failed test case using ITestResult interface in @AfterMethod annotation?

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 can use ITestResult interface in @AfterMethod annotation of testng.
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
What we can do here is, in @AfterMethod annotation, get the status of the test using ITestResult Interface & check if it is failed. If failed then capture the screen shot. As simple as that.
Below Example Explains this.

package screenshotOfFailedTest;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

public class CaptureScreenShotUsingITestResult {

WebDriver driver;

@Test
public void Testcase1(){

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("ajhjhj")).click(); //take incorrect xpath, so that test will fail becuase element does not exist.

}

@AfterMethod
public void TearDown(ITestResult result) throws IOException{

if (result.getStatus() == ITestResult.FAILURE ){
TakesScreenshot ts = (TakesScreenshot)driver;
File srcFile = ts.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("./ScreenShots/"+result.getName()+".jpg"));
//result.getname() method will give you current test case name.
//./ScreenShots/ tell you that, in your current directory, create folder ScreenShots. dot represents current directory
}
}

}

To know about how the same can be achieved using ITestListener, refer below post –
Hope This Helps!!!

 

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 !!!!