Search code examples
javatestng

TestNG: Access input .xml in IAnnotationTransformer class


we try to make use of the "IAnnotationTransformer" Interface to disable tests based on parameters which are passed as CLI parameters in the TestNG.xml file.

However, the IAnnotationTransformer Listener is called at a very early stage of TestNG execution, so that the @BeforeSuite Annotation are not called with TestNG.xml parameters.

How can the parameters of the TestNG.xml file be retrieved, by the IAnnotationTransformer implementation?

We currently have a workaround where we use System.getProperty("sun.java.command"); to manually parse the input parameters. Here, we would have to parse the TestNG.xml file manually.


Solution

  • IAnnotationTransformer cannot be used to work with the TestNG suite file because as you have seen, it gets invoked much earlier in the cycle.

    But you can make use of a IMethodInterceptor implementation that looks like below to get your filtering done. This listener will have access to the testng suite file contents.

    Here's a sample

    import org.testng.annotations.Test;
    
    public class SampleTestClass {
    
        @Test
        public void a() {}
    
        @Test
        public void b() {}
    
        @Test
        public void c() {}
    }
    

    The method interceptor implementation looks like below:

    import org.testng.IMethodInstance;
    import org.testng.IMethodInterceptor;
    import org.testng.ITestContext;
    
    import java.util.List;
    import java.util.Optional;
    import java.util.stream.Collectors;
    
    public class PruneMethods implements IMethodInterceptor {
    
        @Override
        public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
            String[] array = Optional.ofNullable(context.getCurrentXmlTest().getAllParameters().get("methods"))
                    .map(it -> it.split(","))
                    .orElse(new String[0]);
            List<String> filter = List.of(array);
            if (filter.isEmpty()) {
                return methods;
            }
            return methods.stream()
                    .filter(it -> !filter.contains(it.getMethod().getMethodName()))
                    .collect(Collectors.toList());
        }
    }
    

    Suite file would look like below:

    <!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
    <suite name="2980_suite" verbose="2">
        <listeners>
            <listener class-name="com.rationaleemotions.so.qn_78379080.PruneMethods"/>
        </listeners>
        <parameter name="methods" value="a,c"/>
        <test name="2980_test">
            <classes>
                <class name="com.rationaleemotions.so.qn_78379080.SampleTestClass"/>
            </classes>
        </test>
    </suite>