TestNG provides many listeners (as interfaces) which you can customise to your need to get output more readable.
Here are the listeners –
- IAnnotationTransformer
- IAnnotationTransformer2
- IHookable
- IInvokedMethodListener
- IMethodInterceptor
- IReporter
- ISuiteListener
- ITestListener
Source – TestNG Listeners
From this above listeners, in this post we will see ITestListener
ITestListener interface has the following methods to implement
void onStart(ITestContext context)
Invoked after the test class is instantiated and before any configuration method is called.
void onFinish(ITestContext context)
Invoked after all the tests have run and all their Configuration methods have been called.
onTestFailure(ITestResult result)
Invoked each time a test fails.
onTestSkipped(ITestResult result)
Invoked each time a test is skipped.
onTestStart(ITestResult result)
Invoked each time before a test will be invoked.
onTestSuccess(ITestResult result)
Invoked each time a test succeeds.
Let’s see the implementation –
Create a new Maven project (com.testNG and projectName – TestNGSample)
Know more about creating maven project with testNG
Create a testNG class with Passed, Failed and Skipped scenario
TestNG1.java
package mypkg; import org.testng.SkipException; import org.testng.annotations.Test; public class TestNG1 { @Test(description = "Desc - Passing a scenario") public void passTestMethod() { System.out.println("Inside PassTestMethod"); } @Test(description = "Desc - Failing a scenario") public void failTestMethod() { int a = 9/0; System.out.println("Inside FailTestMethod"); } @Test(description = "Desc - Skipping a scenario") public void skipTestMethod() { throw new SkipException("Intentionally skipping"); } }
Create another testNG class – TestNG2.java
package mypkg; import org.testng.Assert; import org.testng.annotations.Test; public class TestNG2 { @Test public void Test1_2(){ System.out.println("This is Test1_2: TESTNG3"); Assert.fail(); } @Test public void Test2_2(){ System.out.println("This is Test2_2: TESTNG2"); } }
Let’s see the output for these 2 testNG classes with out listener
java.lang.ArithmeticException: / by zero at testNG.TList.iTestList.TestNG1.failTestMethod(TestNG1.java:19) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:134) ... Inside PassTestMethod Test ignored. =============================================== Default Suite Total tests run: 3, Passes: 1, Failures: 1, Skips: 1 ===============================================
This is Test1_2: TESTNG3 java.lang.AssertionError: null at org.testng.Assert.fail(Assert.java:97) at org.testng.Assert.fail(Assert.java:102) at testNG.TList.iTestList.TestNG2.Test1_2(TestNG2.java:13) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ... This is Test2_2: TESTNG2 =============================================== Default Suite Total tests run: 2, Passes: 1, Failures: 1, Skips: 0 ===============================================
Now, create a class TestListenerManager.java which will implement ITestListener
package mypkg; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class ITestListManager implements ITestListener { @Override public void onTestStart(ITestResult result) { System.out.println("--------- Test case '"+ result.getMethod().getMethodName() +"' started ---------"); } @Override public void onTestSuccess(ITestResult result) { System.out.println("Testcase '" + result.getMethod().getMethodName() + "' passed"); } @Override public void onTestFailure(ITestResult result) { System.out.println("Testcase '" + result.getMethod().getMethodName() + "' failed, because of " + result.getThrowable()); } @Override public void onTestSkipped(ITestResult result) { System.out.println("Testcase '" + result.getMethod().getMethodName() + "' skipped, because of " + result.getThrowable()); } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } @Override public void onTestFailedWithTimeout(ITestResult result) { } @Override public void onStart(ITestContext context) { System.out.println("Context start- " + context.getName()); } @Override public void onFinish(ITestContext context) { System.out.println("Context finish- " + context.getName()); } }
Now we have 3 class files,
TestNG1.java
TestNG2.java
ITestListManager.java
But we didn’t create relationship between them, means we dint connect the listener class with the actual testNG class
We have 3 ways to integrate
- Class level
- Suite level
- pom.xml using sure-fire plugin
Class level
Each testNG class (TestNG1.java & TestNG2.java), we have to specific the listener as asn example –
@Listeners(mypkg.ITestListManager.class)
public class TestNG2 {
....
@Listeners(mypkg.ITestListManager.class)
public class TestNG2 {
....
Then individually we need to run the testNG classes to see the custom output
Suite level
Listeners can be specified on the testng.xml, so all the tests mentioned under the suite or test tag will be covered
<listeners>
<listener class-name="mypkg.ITestListManager"/>
</listeners>
Example – testng.xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" > <suite name="MySuite For List" verbose="1" > <listeners> <listener class-name="mypkg.ITestListManager"/> </listeners> <test name="Regression1" > <classes> <class name="mypkg.TestNG1"/> </classes> </test> <test name="Functional" > <classes> <class name="mypkg.TestNG2"/> </classes> </test> </suite>
Run the testng.xml – Right click on the xml > Run As > TestNG Suite
OutPut –
Context start- Regression1 --------- Test case 'failTestMethod' started --------- java.lang.ArithmeticException: / by zero at testNG.TList.iTestList.TestNG1.failTestMethod(TestNG1.java:19) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ... Testcase 'failTestMethod' failed, because of java.lang.ArithmeticException: / by zero --------- Test case 'passTestMethod' started --------- Inside PassTestMethod Testcase 'passTestMethod' passed --------- Test case 'skipTestMethod' started --------- Test ignored. Testcase 'skipTestMethod' skipped, because of org.testng.SkipException: Intentionally skipping Context finish- Regression1 Context start- Functional --------- Test case 'Test1_2' started --------- This is Test1_2: TESTNG3 java.lang.AssertionError: null at org.testng.Assert.fail(Assert.java:97) at org.testng.Assert.fail(Assert.java:102) at testNG.TList.iTestList.TestNG2.Test1_2(TestNG2.java:13) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ... Testcase 'Test1_2' failed, because of java.lang.AssertionError: null --------- Test case 'Test2_2' started --------- This is Test2_2: TESTNG2 Testcase 'Test2_2' passed Context finish- Functional =============================================== MySuite For List Total tests run: 5, Passes: 2, Failures: 2, Skips: 1 ===============================================
Now you can observe the customised output, as compared to the raw output we have seen at beginning of this post, this one is more readable.
pom.xml : sure-fire plugin
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M5</version> <configuration> <!--suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles--> <includes> <include>*.*</include> </includes> <properties> <property> <name>listener</name> <value>testNgLearning.listeners.ITestListManager</value> </property> </properties> </configuration> </plugin>
Under your pom.xml, add the sure-fire plugin > properties > property > name as listener and value as ITestListManager or which ever class implemented the ITestListener interface
reference –
https://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html
Now you can run any testng class or method by right click or even we can use mvn test to run the tests, testngListener will automatically applied to each test methods.
To run the tests using maven command in commandline –
mvn test -Dtest=mypkg.TestNG2
If this post is useful, then refer IReporter listener for more customisations.
Reference – TestNG listeners
1 Comment