Piotr Lewandowski
Piotr Lewandowski

Reputation: 6840

How to disable entire test (including inherited methods) in TestNG

I'm using TestNG framework, and many test classes extends Base abstract Test providing some additional information.

I want to set @Test(enabled = false) on whole test class, which is problematic in TestNG as any @Test annotation on method will override first one. Which means, even disabled class, all methods will run anyway.

I found workaround provided by framework authors in pull requests #816 - add listener, that modifies @Test annotations on methods if class that they are defined have @Test(enabled = false):

public class TestClassDisabler implements IAnnotationTransformer {

  @Override
  public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor,
                        Method testMethod) {
    if (testMethod != null) {
      Test test = testMethod.getDeclaringClass().getAnnotation(Test.class);
      if (test != null && !test.enabled()) {
        annotation.setEnabled(false);
      }
    }
  }
}

It works like a charm, however only for tests that don't use inheritance. For this scenario, testMethod.getDeclaringClass() from listener returns original class in which method was declared, not class of object instance that started method.

@Test(enabled = false)
class SpecificTest extends BaseTest {

    @Test
    public void testSomething() {}
}

abstract class BaseTest {

    @Test
    public void veryGenericTest() {}
}

For this example, only testSomething is disabled, veryGenericTest still runs.

Upvotes: 3

Views: 1323

Answers (1)

Piotr Lewandowski
Piotr Lewandowski

Reputation: 6840

IAnnotationTransformer is not good choice here. There is no easy way to get original instance that called method, based only on Method interface. We can only get base class in which method was declared.

Other solution works with IMethodInterceptor, which allows filtering out methods before test suite starts and provides access to test class instance.

public class TestMethodsDisabler implements IMethodInterceptor {

    @Override
    public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
        List<IMethodInstance> testsToRun = new ArrayList<>();

        for (IMethodInstance method : methods) {
            Test testClass = method.getInstance()
                .getClass()
                .getAnnotation(Test.class);

            if (testClass == null || testClass.enabled()) {
                testsToRun.add(method);
            }
        }

        return testsToRun;
    }
}

That way, both standard and inherited methods are disabled when we set @Test(enabled = false) annotation on class.

It's needed to create test suite in testng.xml with this interceptor:

<suite name="ListenersSuite" parallel="false">
    <listeners>
        <listener class-name="your.package.support.TestMethodsDisabler"/>
    </listeners>

    <test name="all-test" preserve-order="true" verbose="2">
        <packages>
            <package name="your.package.tests.*"/>
        </packages>
    </test>
</suite>

Reference

Upvotes: 3

Related Questions