IAnnotationTransformer gets invoked once per multiple listeners
TestNG Version
6.14.3
Expected behavior
IAnnotationTransformer implementation in multiple listeners should get invoked for all the implementations
Actual behavior
IAnnotationTransformer gets invoked once per multiple listeners
Is the issue reproductible on runner?
Yes
- [ Y] Shell
- [ Y] Maven
- [ Y] Gradle
- [ Y] Ant
- [ Y] Eclipse
- [ Y] IntelliJ
- [ Y] NetBeans
Test case sample
Please, share the test case (as small as possible) which shows the issue Attached zip with the testcase and please refer to this topic for more details: https://groups.google.com/forum/#!topic/testng-users/DgjEzL3n5f4 demo.zip
ping @juherr - Any idea on why does TestNG always just consider only 1 annotation transformer ? Also do you think it needs to be addressed in TestNG, given the fact that there are straightforward alternatives (such as the one below) for getting past this issue.
@VineetDuggal
Without any changes in TestNG, here's how you basically get this done at your end (This is exactly what I explained in the testng forums as well, in the thread that you have linked).
The composite annotation transformer could look like below
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;
import org.testng.collections.Lists;
import org.testng.internal.ClassHelper;
public class CompositeTransformer implements IAnnotationTransformer {
private static final String JVM_ARGS =
"com.rationaleemotions.github.issue1894.Listener1, com.rationaleemotions.github.issue1894.Listener2";
private List<IAnnotationTransformer> transformers = Lists.newArrayList();
public CompositeTransformer() {
// Ideally this would get a value from the command line. But just for demo purposes
// I am hard-coding the values.
String listeners = System.getProperty("transformers", JVM_ARGS);
Arrays.stream(listeners.split(","))
.forEach(
each -> {
Class<?> clazz = ClassHelper.forName(each.trim());
IAnnotationTransformer transformer =
(IAnnotationTransformer) ClassHelper.newInstance(clazz);
transformers.add(transformer);
});
}
@Override
public void transform(
ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
for (IAnnotationTransformer each : transformers) {
each.transform(annotation, testClass, testConstructor, testMethod);
}
}
}
Now your suite file would look like below
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="demoissue" configfailurepolicy="continue" verbose="2">
<listeners>
<listener class-name="com.rationaleemotions.github.issue1894.CompositeTransformer"/>
</listeners>
<test name="t1">
<classes>
<class name="com.rationaleemotions.github.issue1894.Test1"/>
</classes>
</test>
</suite>
Now when I run this suite against the zip that you have shared in the google forums thread, here's how the output looks like
...
... TestNG 6.14.3 by Cédric Beust ([email protected])
...
In Transform Listener1
In Transform Listener2
In sampleTest
PASSED: sampleTest
===============================================
t1
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
demoissue
Total tests run: 1, Failures: 0, Skips: 0
===============================================
ping @juherr - Your thoughts on this ?
I don't know why it is not possible to use more than 1 transformer. I don't see drawbacks to have many transformers.
@krmahadevan - newInstance method is deprecated as of TestNG 7.0.0, what are the other options?
@krmahadevan - newInstance method is deprecated as of TestNG 7.0.0, what are the other options?
@samarthyasahu - I didnt understand what you are referring to. Care to elaborate ?
@krmahadevan - newInstance method is deprecated as of TestNG 7.0.0, what are the other options?
@samarthyasahu - I didnt understand what you are referring to. Care to elaborate ?
Referring to this in the CompositeTransformer,
IAnnotationTransformer transformer = (IAnnotationTransformer) ClassHelper.newInstance(clazz);
the newInstance method is no longer there in ClassHelper (https://javadoc.io/static/org.testng/testng/7.0.0/org/testng/internal/ClassHelper.html).
So how to proceed with the above mentioned work around?
@samarthyasahu - You don't need to be relying on an internal helper class from TestNG to do that. You can very well do this on your own by using reflection. Read more here