//
you're reading...
TestNG

“Listen” to what I have to say about “TestNG” Listeners

What are these listeners ? What does TestNG stand to offer to us with them ? This question is something that someone seemed to have. So thought I might as well add up my “2 cents” to un-ravelling its mysteries.

Although I would try my level best to explain what it is, one must never forget that I regard Cedric’s “Next Generation Testing” as my Bible and all that I am now going to blabber have been because I managed to read this book. Hat’s off to Cedric for that ! 🙂

In-case you have done/or exposed to windows programming you would be familiar with the term “events”. Events are specific actions that happen on something for e.g., button clicked! is an event. A simple e.g., would be your mobile plays a sound everytime you get a call.. another event 🙂 Incoming call is an “event” here and your mobile playing a tune is the result of an “event handler” being invoked 🙂 [ Pats his back for that innovative e.g., hehehehe !! Smile will you.. am trying to take away the seriousness here.. sigh! ]

Listeners are basically those entities which are tuned into one or more events that may arise.

TestNG has awesomely managed to leverage this concept and provide a cleaner way of doing things.

So what are TestNG Listeners ?

They are basically “your” classes, which implement some interfaces that TestNG provides, so that when TestNG raises certain events it will look for all “classes” which are basically looking for such events and call the respective event handlers in them.. Confused ??

Its ok to be confused ! I was confused to the core too.

So lets start off with a sample program which will show how to use Listeners.

Here’s a sample Listener that I created, which basically takes care of Starting and Stopping a Selenium Server.

If you look at this listener, its no big complex thing. It is just an ordinary class that implements an Interface named “ISuiteListener”.

Whenever a class implements this listener, TestNG guarantees the end-user that it will invoke the methods onStart() and onFinish() before and after running a TestNG Suite.

So before TestNG picks up your suite for execution, it first makes a call to onStart() method and runs whatever has been scripted in this method. In a similar way, it again makes a call to onFinish() method after a suite has been run.

So what other listeners are there in TestNG ?

There are a lot of listeners. But I will give you an over view on the most common listeners that you would need :

  • org.testng.IReporter : Implement this listener within your class, if you want to customize the TestNG reports (for e.g., you might want your test reports to be available as an excel sheet or a word document or even a pdf for that matter). This would be the last of the calls that TestNG makes before closing your execution.
  • org.testng.IInvokedMethodListener : Implement this listener within your class, if you want something to be done before and after a method is invoked by TestNG. Some classic examples would be, instantiating and closing off the WebDriver for e.g.,.
  • org.testng.IInvokedMethodListener2 : Implement this listener within your class if you want all that IInvokedMethodListener can do, but also give you access to the ITestContext object. ITestContext object essentially is the contextual representation of all the relevant information for a given TestNG run.
  • org.testng.ITestListener : Implement this listener within your class if you want to be notified before and after a test (“<test>”) is run. This would also give you a way in which you can specify as to what should be done when a particular test is passed/skipped/failed etc., (A simple use case would be to implement some sort of a running commentary on the console indicating how many tests have so far run, how many passed and so on and so forth.

Ok, so now am guessing that you must be pretty aware of what listeners are all about and we also saw how to write a listener. Now comes the big question.

How do I let TestNG know that I have such a listener which it should invoke when it is executing my tests ?

There are essentially four ways of adding up a listener to a particular class. I will walk you through on all of the three ways [at-least these are the only ways I know of 🙂 ] :

1. Using the @Listeners TestNG provided annotation.

This is the easiest way of binding your implemented TestNG Listener to your test class.

Before your class definition, you just add up this listener as below

@Listeners(SeleniumStarterListener.class)
public class IUseListeners {

    private Selenium selenium = null;

    @BeforeClass
    public void setup() {
        selenium = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.google.com");
        selenium.start();
    }

    @Test
    public void f() {
        selenium.open("http://www.facebook.com");
    }

    @AfterClass
    public void tearDown() {
        selenium.stop();
    }
}

Here if you notice, I am telling TestNG that for my test class “IUseListeners” I need TestNG to refer to the class SeleniumStarterListener and invoke the corresponding methods within it as and when a relevant TestNG “triggered” event happens. So in this case, TestNG will first invoke my onStart() method in my Listener class before it begins executing my Test (remember, that if you dont provide a suite for your class as I have done here, TestNG creates a default suite, defines a default Test and adds up your testclass to it). That is why I when you execute this sample test along with the listener, the listener takes care of starting the selenium server and stopping it. Clean way of doing it isn’t it ?? That is what TestNG Listeners are there for 🙂

2. By using the <listeners> tag in your TestNG Template file.

Although approach 1 is more than enough to get you started, it’s not an “elegant” way of using Listeners, because you are forced to add this @Listeners section to each of your classes, which you perhaps wont want. So what you do is, you create a TestNG Suite file and then add up the listeners section to this suite file. That way, all of your tests would essentially leverage the listener that you wrote. So in our case, before the suite starts (remember a suite can contain one or more suites within itself, one or more tests within itself and each test<test> can have one or more test classes in it).

So here’s how a typical xml file would look like :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="false">
    <listeners>
        <listener class-name="com.test.listeners.SeleniumStarterListener"/>
    </listeners>
    <test name="Test" preserve-order="false">
        <classes>
            <class name="com.test.IUseListeners" />
        </classes>
    </test>
</suite>

Pay close attention to the <listeners> section here. I have defined this listener at the suite level and have given the “fully qualified name” of my Listener class.

3. When you are working with TestNG class directly and want to pro-grammatically run your Tests you can specify your Listeners as below :

Here’s a sample code which shows you how to do this in a main() program of Java.

public static void main(String[] args){
 TestNG testng = new TestNG();
 Class[] classes = new Class[]{IUseListeners.class};
 testng.addListener(new SeleniumStarterListener());
 testng.setTestClasses(classes);
 testng.run();
 }

So now if you think you are ready for some seriously complicated listeners take a look at this AnnotationTransformer Listener that I managed to create, sometime back..

4. Using the ServiceLoaders approach.

Rather than me duplicating things again, I am going to just point back at the relevant TestNG documentation which talks about this. Please refer here.

Hope that helps you get started working with Listeners..! Phew! On a friday evening when I should be out partying, I end up writing technical blogs… There must be something seriously wrong with me right 🙂 hehehehe.. Dont bother to answer.. I know.. I know it already!

Cheers!

Advertisements

Discussion

21 thoughts on ““Listen” to what I have to say about “TestNG” Listeners

  1. Great post buddy…Seriously cleared my doubts..

    My concern was – How do I let TestNG know that I have such a listener which it should invoke when it is executing my tests ?

    Thanks alot again:)

    Posted by Gulshan | January 28, 2012, 1:56 am
  2. Very well presented. I now understand the logic behind listeners and testNG:)

    Posted by shruthi | February 6, 2013, 10:46 am
  3. Thanks. Saved a day for me…

    Posted by Ravi | March 12, 2013, 3:03 am
  4. Cool Post!
    M new to TestNg so i need your help buddy. I have a need to implement a listener and call that from my test casses and in that listener i have to write code to generate html report for my test run results along with snapshots,

    Could you please help me in this regards, Thanks in advance. You can buzz me in badabapidas@gmail.com

    Posted by bapi | April 20, 2013, 4:01 pm
  5. thank you!!

    Posted by tommy | June 20, 2013, 11:56 pm
  6. Hi Krishnan,

    I have come to your doorstep once again with one of my problems, I have posted a query testng forum , somehow the post is not going through even after subscribing. I am sure you will have a solution for this too. Please see if you can help.

    Thread is this “http://testng.1065351.n5.nabble.com/Retrying-failed-test-cases-automatically-via-maven-custom-listeners-td13869.html”

    my question is this ” I have classes( listeners) which run my tests “n” number of times before leaving them as failed tests. But, all these executions appear in my html report. I would like to change them to either skipped or removed or something custom. I was really excited looking at your solution but I think I have stumbled upon something here, see if you can help please.

    Your two methods “removeIncorrectlyFailedTests(ITestContext test)” and “onStart(ITestContext context)”
    – are both of these methods in the same class
    – which class this class extends
    – which interface this class implements#
    – In the end you have a comment that there are some changes you made to the logic, would you be kind enough to share them.

    Specifically, my implementation doesn’t seem to like “onStart(ITestContext context)”. After trying for a day, I thought it’s best to ask you. “

    Posted by deepankur tyagi | August 5, 2013, 7:57 pm
    • I am not sure about this question. Seems like you pasted the same question in both the places.

      Just take a look at the listener interfaces and it should tell you a lot. With respect to your question the answers are as below:

      1. The remove method seems to be added in a class that is extending the HtmlReporter that TestNG gives you.

      2. The second method can be in the same class but make sure you are implementing the ITestListener.

      For any further queries I would suggest that you please post on the TestNG-users google forum.

      Posted by Confusions Personified | August 21, 2013, 7:01 am
  7. Hey nice post.. Thanks for sharing your knowledge on testing listeners

    Posted by Aquasush | February 28, 2014, 4:56 am
  8. Nice post brother.

    Posted by Tarique Khan | August 6, 2014, 6:27 pm
  9. Grt Article! I liked your signature in all posts “All desirable things in life are either illegal, flattening, expensive or in love with someone else”

    BTW, can we create a listener i.e which starts a webdriver and stops. also listener should be capable of running same tests in different browsers(if specified more than one)?

    Posted by Vishwas | September 28, 2014, 11:45 am
  10. Listeners were like a strange things in testng until i read this post…great job bro..thanks a lot..

    Posted by Manjunath | September 29, 2014, 1:59 pm
  11. Hi.
    In my Tests I am using CustomReporter class which implements the IReporter.This listener I have specified in testng.xml file.But this is executing only once per entire test suite.Why it is not executing for every .Below is the code of CustomReporter and testng.xml

    my requirement is to generate the single report for multiple tests() and should be stored on remote machine.How can I achieve this.Please help me..

    CustomReporter.java
    public class CustomReporter implements IReporter
    {
    File fd = new File(“”);
    String date;
    static DateFormat df = new SimpleDateFormat(“yyyy-MM-dd_hh”);
    public static final String folderNameWithTimeStamp = df.format(new Date());
    String currentDir = System.getProperty(“user.dir”) + “//Reports//”;
    String smbUrl = “//ipaddress//d//reports//”;
    String finalPath = smbUrl + folderNameWithTimeStamp;

    @SuppressWarnings(“deprecation”)
    @Override
    public void generateReport(List xmlSuites, List suites, String outputDirectory)
    {
    TestNG.getDefault().setOutputDirectory(finalPath);
    TestNG.getDefault().setXmlSuites(xmlSuites);
    XmlSuite suite = new XmlSuite();
    List suites1 = new ArrayList();
    suites1.add(suite);
    TestNG tng = new TestNG();
    tng.setXmlSuites(suites1);

    }

    Posted by Ravinder Reddy | December 2, 2014, 9:49 pm
  12. I am struggling with a problem plz help…..The scenario is like this….there is a web table column having some integer values I have to verify that they are in ascending order or not.I have a solution that first i collect all the element of the column and store them in TreeSet which will give me data in shorted order and then i will use List to collect the same data and then i can use for loop and If loop along with assert to verify ……but my confusion is …I will use driver.findElement for the purpose which will return me webelement and I need String value to use method String.equals(String1)…………………plz suggest what to do…..or do u have any other approach..

    Posted by Gunjan kumar | January 26, 2015, 12:53 am
  13. Hi,
    i have a question, is there any way we can retry to run failed @beforeclass /@afterclass methods
    i know how to retry on @test failure : http://seleniumeasy.com/testng-tutorials/execute-only-failed-test-cases-using-iretryanalyzer
    but not able to find any way for @beforeclass.

    Posted by Alpana Chauhan | January 27, 2015, 3:03 pm
  14. Thanks a lot Sir..

    Posted by Santhosh | May 4, 2015, 5:12 pm
  15. Hey, thanks for the awesome article. Just a concern… The link for sample listener at the start of the article no longer works.

    Please correct it if possible.

    Thanks again

    Posted by Deep Sukhwani | July 8, 2015, 4:10 pm
  16. Suppose you write a listener that is going to be specific to a certain test suite (not really general purpose). Then here’s a fourth way:

    Relying on the fact that any test class annotated with @Listeners makes that listener available to the entire suite (not just to the one annotated class, as is kind of implied above), consider that a listener can itself be a test class!

    Specifically: a) Put your listener class in the same place as the rest of the test classes in your suite. b) Put a @Listeners annotation in front of it referring to itself. c) Add a method annotated with @Test inside the listener class. Now the listener class will be identified as a test class, and it has an @Listener annotation which will be respected, and thus it will itself be a listener.

    Note that your test method in the listener class can have @Test(enabled=false) (so it doesn’t pollute your results) and it still works!

    Your article got me started with my first TestNG listener and led me to figure this bit out. Thanks!

    Posted by David Bakin | August 6, 2015, 1:18 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: