Skip to main content

How to Exclude @Flaky Tests in TestNG

Problem Statement

In large-scale test automation, some tests may be flaky—they fail intermittently due to environmental issues, race conditions, or external dependencies. Running these tests in a CI/CD pipeline (e.g., Jenkins) can lead to unreliable build results.

To avoid unnecessary failures, we need a way to mark such tests as flaky and ensure they are automatically excluded from test execution in the pipeline.

Solution Approach

1. Define a Custom @Flaky Annotation

We create a custom Java annotation @Flaky that marks a test as flaky.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Flaky {
}

2. Implement a TestNG IMethodInterceptor

TestNG provides an IMethodInterceptor interface that allows dynamic filtering of test methods. We implement an interceptor that checks if a test method is annotated with @Flaky and excludes it from execution.

import org.testng.IMethodInstance;
import org.testng.IMethodInterceptor;
import org.testng.ITestContext;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

public class FlakyTestInterceptor implements IMethodInterceptor {
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
return methods.stream()
.filter(method -> {
Method testMethod = method.getMethod().getConstructorOrMethod().getMethod();
return !testMethod.isAnnotationPresent(Flaky.class);
})
.collect(Collectors.toList());
}
}

3. Apply the Interceptor in TestNG Configuration

Modify the testng.xml file to register the interceptor as a listener.

<suite name="TestSuite">
<listeners>
<listener class-name="com.example.FlakyTestInterceptor"/>
</listeners>
<test name="RegressionTests">
<classes>
<class name="com.example.SampleTest"/>
</classes>
</test>
</suite>

4. Annotate Tests with @Flaky

Now, mark the flaky tests using the @Flaky annotation. These tests will be excluded automatically.

import org.testng.annotations.Test;

public class SampleTest {

@Test
public void stableTest() {
System.out.println("This test should always run.");
}

@Test
@Flaky
public void flakyTest() {
System.out.println("This test should be excluded.");
}
}

5. Running Tests in Jenkins

Since FlakyTestInterceptor dynamically excludes flaky tests, no additional configuration is needed in Jenkins. The standard Maven or Gradle commands will work as expected.

pipeline {
agent any
stages {
stage('Build and Test') {
steps {
script {
sh 'mvn clean test' // If using Maven
sh 'gradle test' // If using Gradle
}
}
}
}
}

Conclusion

✅ The IMethodInterceptor dynamically filters out @Flaky tests at runtime. ✅ No need to modify testng.xml for each test—just annotate the test with @Flaky. ✅ Jenkins runs only stable tests, preventing flaky failures from breaking the build.

This ensures a reliable, maintainable, and automated approach to handling flaky tests in TestNG! 🚀