ITestListener and aftermethod

1,673 views
Skip to first unread message

webtester

unread,
May 16, 2012, 7:49:44 AM5/16/12
to testng-users
Hi,

I like to use the ITestListener to customize the testresults.

I see the following sequence when executing tests:

onStart
onTestStart
testOne
onTestFailure
aftermethod

In the aftermethod I collect log information and I capture a
screenshot (with webdriver)

I use ITestResult tr in the after method to set attributes. I like to
use those values in the listener.

Is it possible to change the order of execution? So we get:
(aftermethod before listener)

onStart
onTestStart
testOne
aftermethod
onTestFailure

Or do you suggest something else?


Thanks,
R

Krishnan Mahadevan

unread,
May 16, 2012, 8:42:30 AM5/16/12
to testng...@googlegroups.com
Here's a ugly hack which doesnt use @AfterMethod but uses the @Test method itself to pack attributes, which can later be extracted from your listener.

Note: I dont know how this would work, if you try to couple your @Test annotated test method to work with either @Parameters annotation or with a dataProvider 


@Listeners(HelloListener.class)
public class Sample {
@Test
public void f(ITestContext context, Method incomingMethod) {
for (Object eachMethod : context.getSuite().getAllInvokedMethods().toArray()) {
IInvokedMethod invokedMethod = (IInvokedMethod) eachMethod;
if (incomingMethod == invokedMethod.getTestMethod().getConstructorOrMethod().getMethod()) {
System.out.println("found the current method " + incomingMethod.getName());
invokedMethod.getTestResult().setAttribute("name", "krishnan");
}
}
}
}

Here's my listener class : //Just showing the relevant sections of the listener class

public class HelloListener implements ITestListener {
@Override
public void onTestSuccess(ITestResult result) {
System.out.println("success " + result.getAttribute("name"));
}
}

Output:
[TestRunner] Starting executor for test Default test with time out:2147483647 milliseconds.
found the current method f
success krishnan
After method
PASSED: f(org.testng.TestRunner@5797627b, public void com.krishnan.Sample.f(org.testng.ITestContext,java.lang.reflect.Method))




Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"



--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.


webtester

unread,
May 16, 2012, 9:31:53 AM5/16/12
to testng-users
I hope there is also another solution...

In the aftermethod I like to determine if the test passed / failed.
(because I need the driver instance to create a screenshot)

Then with the listener I like to process the results.



On May 16, 2:42 pm, Krishnan Mahadevan

Krishnan Mahadevan

unread,
May 16, 2012, 10:23:25 PM5/16/12
to testng...@googlegroups.com
You could still pack the driver instance itself as an attribute to your ITestResult object within your Test method, and then work with it in onTestFailure(ITestResult result) 

Wouldnt that work ?

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"

Lolz ha ha ha

unread,
Nov 4, 2012, 12:44:47 PM11/4/12
to testng...@googlegroups.com
Hi,

I found this useful. I want your help. I have 100 test cases and want to take screenshots of the failed test cases using Ilisteners. I dnt know how to implement. can you please help me in doing that. I am available at nitin...@gmail.com.

Please reply.

Thank You
Nitin

Devon Jones

unread,
Apr 15, 2016, 1:04:10 PM4/15/16
to testng-users
When I attempted to put my 'screenshot upon failure' in my onTestFailure method, the @AfterMethod didn't trigger after the tests and I had a ton of open browsers. When I moved it into my @AfterMethod, everything worked fine. Has anyone else had that issue or know how to solve it?

⇜Krishnan Mahadevan⇝

unread,
Apr 17, 2016, 1:20:06 AM4/17/16
to testng...@googlegroups.com
Devon,
Do you have a reproducible test which can be executed to recreate your problem ? @AfterMethod is designed to run always [even if a test method fails ]

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Technical Scribbings @ http://rationaleemotions.wordpress.com/

--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testng-users...@googlegroups.com.

To post to this group, send email to testng...@googlegroups.com.

Devon Jones

unread,
Apr 18, 2016, 11:10:29 AM4/18/16
to testng-users
Yes, let me share my code below. If I comment out the ITestResult parameter and lines 65-67 in my @AfterMethod and uncomment out line 19 in my TestListener file, a screenshot will not be taken and my browser will not be closed.  

package com.selenium.test.webtestsbase;

import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;


/**
* Created by devonjones on 4/14/16.
*/
public class TestListeners extends TestListenerAdapter {
public static WebDriver driver;

public void onTestSuccess(ITestResult result) {
System.out.println(result.getName() + " was successful.");
}

public void onTestFailure(ITestResult result) {
//ScreenShots.captureScreenShot(driver, result.getName());
System.out.println(result.getName() + " failed.\n Throwable: " + result.getThrowable().getMessage());

}

public void onTestSkipped(ITestResult result) {
System.out.println(result.getName() + " was skipped.");

}
}

package com.selenium.test.webtestsbase;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

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

/**
* Created by devonjones on 4/14/16.
*/
public class ScreenShots {
public static WebDriver driver;

public static void captureScreenShot(WebDriver driver, String name) {
File source = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(source, new File("target/screenshots/" + name + ".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}

@AfterMethod
public void logoutAndCleanUp(ITestResult result) {
if (ITestResult.FAILURE == result.getStatus()) {
ScreenShots.captureScreenShot(driver, result.getName());
}
this.driver.quit();
ordersPage = null;
emberTable = null;
//createOrderPage = null;
commonUsefulMethods = null;
}

⇜Krishnan Mahadevan⇝

unread,
Apr 18, 2016, 11:31:58 PM4/18/16
to testng...@googlegroups.com
Devon,

Can you please share a full reproducible case, which I can execute to recreate the problem ? With the different pieces you shared, its difficult to identify what is going on, because you dont show how the WebDriver reference is being passed around.

So please help create a standalone test along with the required listeners which I can use to run your test and recreate your problem.

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/
My Technical Scribbings @ http://rationaleemotions.wordpress.com/

Devon Jones

unread,
Apr 19, 2016, 11:05:28 AM4/19/16
to testng...@googlegroups.com
Sure, thanks for taking the time :). I've included my login method and the test method I was trying to run (just a basic 'Am I on the page I want to be on').

OrdersPage ordersPage;
//CreateOrderPage createOrderPage;
public WebDriver driver;

/**
* Returns true if the orders pages loads and header is visible
*
* @return
*/
public boolean onOrdersPage() throws InterruptedException {
waitForOrdersPageToLoad();
String navText = EmberTable.navBarHeader.getText();
return navText.equalsIgnoreCase("Orders") && orderFiltersHeader.isDisplayed();
}

public void waitForOrdersPageToLoad() {
CommonUsefulMethods.waitUntilElementVisable(driver, EmberTable.firstColumnHeader);
}

/**
* Created by devonjones on 12/10/15.
*/
public class OrdersTest {
OrdersPage ordersPage;
EmberTable emberTable;
//CreateOrderPage createOrderPage;
CommonUsefulMethods commonUsefulMethods;
private static final String navigationURL = "https://qa1.digabit.com/Portal/ecommerceOrderManagement/#/orders";
public WebDriver driver;
HashMap<String, String> loginMap;

// Factory and map to run all tests against both regular and admin users
@Factory(dataProvider = "login", dataProviderClass = LoginData.class)
public OrdersTest(String userType, String userName, String password) {
loginMap = new HashMap<String, String>();
loginMap.put("usertype", userType);
loginMap.put("username", userName);
loginMap.put("password", password);
}

@BeforeMethod
public void loginAndNavigateToOrders() {
driver = new FirefoxDriver();
Login login = PageFactory.initElements(driver, Login.class);
login.simpleLogin(driver, loginMap.get("username"), loginMap.get("password"), navigationURL);
ordersPage = new OrdersPage();
ordersPage.driver = driver;
PageFactory.initElements(driver, ordersPage);
emberTable = new EmberTable();
emberTable.driver = driver;
PageFactory.initElements(driver, emberTable);
//createOrderPage = new CreateOrderPage();
// createOrderPage.driver = driver;
//PageFactory.initElements(driver, createOrderPage);
commonUsefulMethods = new CommonUsefulMethods();
PageFactory.initElements(driver, commonUsefulMethods);
commonUsefulMethods.driver = driver;
    }

@AfterMethod
public void logoutAndCleanUp(ITestResult result) {
if (ITestResult.FAILURE == result.getStatus()) {
ScreenShots.captureScreenShot(driver, result.getName());
}
this.driver.quit();
ordersPage = null;
emberTable = null;
//createOrderPage = null;
commonUsefulMethods = null;
}

    /**
* @author djones
* <b> Test: </b>TC-297- Order Page loads
* <b> Test Steps: </b><br>
* <ul>
* <li> 1. Login as any user</li>
* <li> 2. Navigate to orders page </li>
* </ul>
* <b> Validation: </b Verify Orders table header and Filters header present<br>
*/
@Test
public void testOnOrdersPage() throws InterruptedException {
ordersPage.waitForOrdersPageToLoad();
Assert.assertTrue(ordersPage.onOrdersPage(), "Not on orders page");
}

--
You received this message because you are subscribed to a topic in the Google Groups "testng-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/testng-users/rgwE2QD5QwI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to testng-users...@googlegroups.com.

⇜Krishnan Mahadevan⇝

unread,
Apr 19, 2016, 11:03:07 PM4/19/16
to testng...@googlegroups.com
Devon,

I wasn't able to run your sample test that you provided because I don't have all the page objects and I also don't have access to the URL you shared. [ I was hoping that you would create a sample which I can execute ].

All said and done, I went ahead and created a sample to demonstrate the fact that I can't recreate your issue.

Here's my listener [ its pretty much the same thing that you shared, but I just added a few tweaks to it ]

public class TestListeners extends TestListenerAdapter {
    public void onTestSuccess(ITestResult result) {
System.out.println(result.getName() + " was successful.");
}

public void onTestFailure(ITestResult result) {
        Object testClassInstance = result.getInstance();
if (testClassInstance instanceof WebDriverEnabled) {
RemoteWebDriver driver = ((WebDriverEnabled) testClassInstance).getDriver();

captureScreenShot(driver, result.getName());
}
System.out.println(result.getName() + " failed.\n Throwable: " + result.getThrowable().getMessage());

}

public void onTestSkipped(ITestResult result) {
System.out.println(result.getName() + " was skipped.");

}

    public static void captureScreenShot(RemoteWebDriver driver, String name) {
File source = driver.getScreenshotAs(OutputType.FILE);

try {
FileUtils.copyFile(source, new File("target/screenshots/" + name + ".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}

import org.openqa.selenium.remote.RemoteWebDriver;

/**
* This interface exposes out the RemoteWebDriver instance from its implementation.
* A typical use case would be for Test Classes to implement this method so that they may expose the
* {@link RemoteWebDriver} driver instance that they create internally to outside callers such as listeners
* which may need access to the driver object for performing various operations.
*/
public interface WebDriverEnabled {
RemoteWebDriver getDriver();
}
Here's my test class 

@Listeners (TestListeners.class)
public class SampleTestClass implements WebDriverEnabled {
private RemoteWebDriver driver;
private boolean simulateFailure;

@BeforeMethod
public void beforeMethod() {
driver = new FirefoxDriver();
}

@Factory (dataProvider = "dp")
public SampleTestClass(boolean simulateFailure) {
this.simulateFailure = simulateFailure;
}


@Test
public void testMethod() {
driver.get("http://the-internet.herokuapp.com/");
if (simulateFailure) {
driver.findElement(By.id("youCantSeeMe"));
}
}

@AfterMethod
public void afterMethod() {
if (driver != null) {
driver.quit();
}
}

@DataProvider (name = "dp")
public static Object[][] getData() {
return new Object[][] {
{false}, {true}
};
}

@Override
public RemoteWebDriver getDriver() {
return driver;
}
}
Please feel free to tweak this example if needed so that it can simulate your issue. FWIW I am using TestNG's latest released version [ 6.9.11]

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/
My Technical Scribbings @ http://rationaleemotions.wordpress.com/

Reply all
Reply to author
Forward
0 new messages