How to disable TestNG test based on a condition

45,181

Solution 1

You have two options:

Your annotation transformer would test the condition and then override the @Test annotation to add the attribute "enabled=false" if the condition is not satisfied.

Solution 2

An easier option is to use the @BeforeMethod annotation on a method which checks your condition. If you want to skip the tests, then just throw a SkipException. Like this:

@BeforeMethod
protected void checkEnvironment() {
  if (!resourceAvailable) {
    throw new SkipException("Skipping tests because resource was not available.");
  }
}

Solution 3

There are two ways that I know of that allow you the control of "disabling" tests in TestNG.

The differentiation that is very important to note is that SkipException will break out off all subsequent tests while implmenting IAnnotationTransformer uses Reflection to disbale individual tests, based on a condition that you specify. I will explain both SkipException and IAnnotationTransfomer.

SKIP Exception example

import org.testng.*;
import org.testng.annotations.*;

public class TestSuite
{
    // You set this however you like.
    boolean myCondition;
    
    // Execute before each test is run
    @BeforeMethod
    public void before(Method methodName){
        // check condition, note once you condition is met the rest of the tests will be skipped as well
        if(myCondition)
            throw new SkipException();
    }
    
    @Test(priority = 1)
    public void test1(){}
    
    @Test(priority = 2)
    public void test2(){}
    
    @Test(priority = 3)
    public void test3(){}
}

IAnnotationTransformer example

A bit more complicated but the idea behind it is a concept known as Reflection.

Wiki - http://en.wikipedia.org/wiki/Reflection_(computer_programming)

First implement the IAnnotation interface, save this in a *.java file.

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;

public class Transformer implements IAnnotationTransformer {

    // Do not worry about calling this method as testNG calls it behind the scenes before EVERY method (or test).
    // It will disable single tests, not the entire suite like SkipException
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod){

        // If we have chose not to run this test then disable it.
        if (disableMe()){
            annotation.setEnabled(false);
        }
    }

    // logic YOU control
    private boolean disableMe() {
    }
}

Then in you test suite java file do the following in the @BeforeClass function

import org.testng.*;
import org.testng.annotations.*;

/* Execute before the tests run. */    
@BeforeClass
public void before(){

    TestNG testNG = new TestNG();
    testNG.setAnnotationTransformer(new Transformer());
}

@Test(priority = 1)
public void test1(){}

@Test(priority = 2)
public void test2(){}

@Test(priority = 3)
public void test3(){}

One last step is to ensure that you add a listener in your build.xml file. Mine ended up looking like this, this is just a single line from the build.xml:

<testng classpath="${test.classpath}:${build.dir}" outputdir="${report.dir}" 
    haltonfailure="false" useDefaultListeners="true"
    listeners="org.uncommons.reportng.HTMLReporter,org.uncommons.reportng.JUnitXMLReporter,Transformer" 
    classpathref="reportnglibs"></testng>

Solution 4

A Third option also can be Assumption Assumptions for TestNG - When a assumption fails, TestNG will be instructed to ignore the test case and will thus not execute it.

  • Using the @Assumption annotation
  • Using AssumptionListener Using the Assumes.assumeThat(...) method

You can use this example: Conditionally Running Tests In TestNG

Solution 5

I prefer this annotation based way for disable/skip some tests based on environment settings. Easy to maintain and not requires any special coding technique.

  • Using the IInvokedMethodListener interface
  • Create a custom anntotation e.g.: @SkipInHeadlessMode
  • Throw SkipException
public class ConditionalSkipTestAnalyzer implements IInvokedMethodListener {
    protected static PropertiesHandler properties = new PropertiesHandler();

    @Override
    public void beforeInvocation(IInvokedMethod invokedMethod, ITestResult result) {
        Method method = result.getMethod().getConstructorOrMethod().getMethod();
        if (method == null) {
            return;
        }
        if (method.isAnnotationPresent(SkipInHeadlessMode.class)
                && properties.isHeadlessMode()) {
            throw new SkipException("These Tests shouldn't be run in HEADLESS mode!");
        }
    }

    @Override
    public void afterInvocation(IInvokedMethod iInvokedMethod, ITestResult iTestResult) {
        //Auto generated
    }
}

Check for the details: https://www.lenar.io/skip-testng-tests-based-condition-using-iinvokedmethodlistener/

Share:
45,181

Related videos on Youtube

Afamee
Author by

Afamee

Software QA Engineer with Alibris.com

Updated on July 09, 2022

Comments

  • Afamee
    Afamee almost 2 years

    Is there currently a way to disable TestNG test based on a condition

    I know you can currently disable test as so in TestNG:

    @Test(enabled=false, group={"blah"})
    public void testCurrency(){
    ...
    }
    

    I will like to disable the same test based on a condition but dont know how. something Like this:

    @Test(enabled={isUk() ? false : true), group={"blah"})
    public void testCurrency(){
    ...
    }
    

    Anyone has a clue on whether this is possible or not.

    • matt b
      matt b over 13 years
      Annotations aren't executable code, so this is unlikely. What are you really trying to do - in what conditions would you want a test to be run or not run?
    • Afamee
      Afamee over 13 years
      thanks matt. See cedrics answer below for more details.
  • Afamee
    Afamee over 13 years
    Thanks cedric. I think i will like to explore the 'annotation transformer' option. that sounds more like what am looking for.
  • Afamee
    Afamee over 13 years
    Thanks again. It didnt take me long to get a working example of this transformer. One thing though is not behaving as i expected. I want to dynamically transform the name of the test that i run (...at least the way it will be displayed on the test result) by calling annot.setTestName(concatString) where annot represents the method annotation but result comes back with original name unchanged. Is there another way to do this?? Hopefully didnt confuse u.
  • Cedric Beust
    Cedric Beust over 13 years
    You won't be able to override the behavior of a class at runtime, that's just how Java is designed. Instead, I suggest you put the logic that decides what that name is directly into the test so you can return it in getTestName().
  • Afamee
    Afamee over 13 years
    that is exactly what I did. I thought setTestName("newName") was meant to change the name of the test. I understand calling getTestName() to get name based on logic in test code but then I want to set this newly retrieved name for the test by saying annot.setTestName(newName) or annot.setTestName(getTestName()+"_Modified"). When the test completes, it still has the original name and not the modified name.
  • Rameshwar
    Rameshwar over 6 years
    Can this be achieved? - I want to disable TestB if TestA has failed.
  • Mike G.
    Mike G. over 6 years
    Hi, since 6.13 throwing SkipException sets status to Failed instead of Skipped. See stackoverflow.com/questions/20022288/…
  • dpr
    dpr about 5 years
    The documentation of SkipException refers to the deprecated '@Configuration annotation. This might explain the described behavior for '@BeforeMethod, etc.
  • djangofan
    djangofan almost 5 years
    Doesn't enabled=false check occur at an even earlier stage of the test than BeforeMethod? In some cases, using enabled=false would be better than using Before-hook, IMHO.