testng icon indicating copy to clipboard operation
testng copied to clipboard

IAnnotationTransformer gets invoked once per multiple listeners

Open VineetDuggal opened this issue 7 years ago • 7 comments

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

VineetDuggal avatar Aug 10 '18 14:08 VineetDuggal

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
===============================================

krmahadevan avatar Aug 11 '18 04:08 krmahadevan

ping @juherr - Your thoughts on this ?

krmahadevan avatar Nov 09 '18 02:11 krmahadevan

I don't know why it is not possible to use more than 1 transformer. I don't see drawbacks to have many transformers.

juherr avatar Nov 09 '18 08:11 juherr

@krmahadevan - newInstance method is deprecated as of TestNG 7.0.0, what are the other options?

samarthyasahu avatar Jan 25 '23 08:01 samarthyasahu

@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 avatar Jan 25 '23 08:01 krmahadevan

@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 avatar Jan 25 '23 08:01 samarthyasahu

@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

krmahadevan avatar Jan 25 '23 08:01 krmahadevan