Ingo Kegel
Ingo Kegel

Reputation: 48105

Detect test failure in testng @AfterMethod

I want to take a screenshot if a test fails. Rather than wrapping all test methods with try/catch blocks, I would like to add this logic to the method annotated with @AfterMethod.

How can I detect in the method annotated with @AfterMethod if the current test has failed?

Upvotes: 21

Views: 24405

Answers (4)

Nathan Ripert
Nathan Ripert

Reputation: 890

Variant to the previous answers:

Since you already know that you want to take the screenshot only in case of failure, you can use onTestFailure() method from TestListenerAdapter:

import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

public class LFailure extends TestListenerAdapter {

@Override
public void onTestFailure(ITestResult tr) {
    System.out.println("Failure");
    // your screenshot code
    }
}

PS: don't forget to add LFailure to your testng.xml, or directly in the code like this:

@Listeners({ LFailure.class })

(preferably in a base class, from which all your tests inherit)

Upvotes: 2

niharika_neo
niharika_neo

Reputation: 8531

It would be good if you can implement a listener IInvokedMethodListener and implement the afterInvocation() method. This gives you access to the result object of your method. You can put your code to take a screenshot here.

Upvotes: 1

thekevinmonster
thekevinmonster

Reputation: 387

A good option is to use an ITestListener instead of handling failure reporting in @AfterMethod. The test listener's onTestFailed() function will be called after your test method has run, but before the @AfterMethod method has run. (Note that there is not an onTestFinished() function in the listener; that role is fulfilled by @AfterMethod.)

To make things easier on yourself, you can use a TestListenerAdapter, which will implement all of the other functions that you don't specifically @Override yourself.

What you end up with is:

public class MyTestListener extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult result){
    yourTakeScreenShotFunctionHere();
   }
}

You then attach the listener to your test class with

@Listeners({MyTestListener.class})
public class MyTestClass(){etc}

The ITestResult is a reference to your test class's object, so you can use reflection to grab data out of it such as a Selenium WebDriver instance, etc.

You can have as many different listeners as you want, to do various things such as clean up or preserve error logs, take screenshots, trigger other reporting functionality, send emails, or whatever you want.

Upvotes: 8

JacekM
JacekM

Reputation: 4099

If the method annotated with @AfterMethod has an ITestResult parameter then TestNG will automatically inject the result of the test. (source: TestNG documentation, section 5.18.1)

This should do the job:

@AfterMethod
public void tearDown(ITestResult result) {
   if (result.getStatus() == ITestResult.FAILURE) {
      //your screenshooting code goes here
   }        
}

Upvotes: 35

Related Questions