Exploring TestNG Listeners for controlled Execution - IAnnotationTransformer

There might be scenarios where we want to execute TestNG tests based on some condition or criteria that is evaluated dynamically while test execution is in progress.

For example,

  1. Enable or disable a test
  2. Add data provider at run time 

IAnnotationTransformer listener is the solution and it is defined as an interface that modifies the default TestNG tests behavior at run time. Using this listener, we can modify values of all attributes defined in @Test annotation by calling their setters.

Let's assume that we have a requirement where we should skip tests that are tagged to a specified group without changing testng suite every time. These kind of requirements often comes up when we are triggering testng suite from CI tool which is linked to repository to get source code and we don't want to change/commit test suite after updating groups every time before running tests. 

Test Class:

import org.testng.annotations.Test;

public class ListenerTest {
	
	@Test(groups={"smokeTest","regressionTest"})
	public void test1() {
		System.out.println("I am test1");
	}
	
	@Test(groups={"regressionTest"})
	public void test2() {
		System.out.println("I am test2");
	}
}

Annotation Transformer Listener Class:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import java.util.Arrays;
import java.util.List;

import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;

public class AnnotationTransformerListener implements IAnnotationTransformer {

	@Override
	public void transform(ITestAnnotation annotation, Class testClass,
			Constructor testConstructor, Method testMethod) {
		
		List<String> groupNames = Arrays.asList(annotation.getGroups());
		
		//Value 'smokeTest' can be read from many places like properties file, run time parameter etc...
		//For Simplicity, group is read from run time argument in this program
		
		String groupNameToSkip = System.getProperty("SkipGroup");
		
		if(groupNames.contains(groupNameToSkip)){
			annotation.setEnabled(false);
		}
	}

}
 
  

TestNG Suite:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="classes" thread-count="2">

  <listeners>
    <listener class-name="test.listeners.AnnotationTransformerListener"></listener>
  </listeners>

  <test name="Test">
    <classes>
      <class name="test.listeners.ListenerTest"/>
    </classes>
  </test>
</suite>
 
  

AnnotationTransformerListener is test annotation transformer listener class and implements IAnnotationTransformer. Method 'transform()'' implemented from IAnnotationTransformer transforms the @Test annotation.

This method takes four parameters. First parameter is of type ITestAnnotation which represents @Test annotation. 

@Test annotation can be used at class, constructor or method level. Last three parameters helps to identify on which Java element the annotation was found: a class, a constructor, or a method. Only one of them will be non-null.

IAnnotationTransformer works, only when specified in testng suite xml file and will not work when specified in the @Listeners annotation. The @Listeners annotation can contain any class that extends org.testng.ITestNGListener except IAnnotationTransformer. The reason is that IAnnotationTransformer listener needs to be known very early in the process so that TestNG can use them to rewrite annotations; Therefore this listener needs to be specified in testng suite xml(testng.xml) file. 

This is just an example how listeners can be used efficiently. Please share your experience with TestNG listeners in comments, if you have any.

要查看或添加评论,请登录

Arunkumar Velusamy的更多文章

社区洞察

其他会员也浏览了