javatestngtestng-eclipse

How do I set the InvocationCount at runtime in TestNG - @Test?


I want to run my Test methods multiple times based on a business logic. Is there a way to alter InvocationCount to achieve the same ? any other suggestions are also welcome.


Solution

  • You would need to basically leverage an IAnnotationTransformer for doing this.

    Here's a sample that shows this in action.

    The marker annotation which we are going to be using to indicate that a particular test method needs to be run more than once.

    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    import static java.lang.annotation.ElementType.METHOD;
    
    /**
     * A Marker annotation which is used to express the intent that a particular test method
     * can be executed more than one times. The number of times that a test method should be
     * iterated is governed by the JVM argument : <code>-Diteration.count</code>. The default value
     * is <code>3</code>
     */
    @Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
    @Target({METHOD})
    public @interface CanRunMultipleTimes {
    }
    

    The test class looks like this.

    import org.testng.annotations.Test;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class TestClassSample {
        private volatile AtomicInteger counter = new AtomicInteger(1);
    
        @CanRunMultipleTimes
        @Test
        public void testMethod() {
            System.err.println("Running iteration [" + counter.getAndIncrement() + "]");
        }
    }
    

    Here's how the annotation transformer looks like.

    import org.testng.IAnnotationTransformer;
    import org.testng.annotations.ITestAnnotation;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    public class SimpleAnnotationTransformer implements IAnnotationTransformer {
        @Override
        public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
            if (testMethod == null || testMethod.getAnnotation(CanRunMultipleTimes.class) == null) {
                return;
            }
    
            int counter = Integer.parseInt(System.getProperty("iteration.count", "3"));
            annotation.setInvocationCount(counter);
        }
    }
    

    Here's how the suite xml file looks like:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="46998341_Suite" verbose="2">
        <listeners>
            <listener class-name="com.rationaleemotions.stackoverflow.qn46998341.SimpleAnnotationTransformer"/>
        </listeners>
        <test name="46998341_Test">
            <classes>
                <class name="com.rationaleemotions.stackoverflow.qn46998341.TestClassSample"/>
            </classes>
        </test>
    </suite>
    

    Here's how the output would look like :

    ... TestNG 6.12 by Cédric Beust (cedric@beust.com)
    ...
    Running iteration [1]
    Running iteration [2]
    Running iteration [3]
    PASSED: testMethod
    PASSED: testMethod
    PASSED: testMethod
    
    ===============================================
        46998341_Test
        Tests run: 3, Failures: 0, Skips: 0
    ===============================================
    
    ===============================================
    46998341_Suite
    Total tests run: 3, Failures: 0, Skips: 0
    ===============================================