Careeroza
Retry Analyzer for Flaky Tests
IRetryAnalyzer
Sometimes a test fails because of the environment (a slow QA server, a network blip), not a bug. A retry analyzer re-runs a failed test a limited number of times. Use it as a safety net, not as a fix: a test that often needs retries must be investigated.
public class RetryAnalyzer implements IRetryAnalyzer {
private static final int MAX_RETRIES = 2;
private int attempt = 0;
@Override
public boolean retry(ITestResult result) {
if (attempt < MAX_RETRIES) {
attempt++;
System.out.println("Retrying " + result.getName() + " (" + attempt + "/" + MAX_RETRIES + ")");
return true; // run the test again
}
return false;
}
}
// apply to one test
@Test(retryAnalyzer = RetryAnalyzer.class)
public void placeOrderWithUpi() { ... }Applying It to Every Test
public class RetryTransformer implements IAnnotationTransformer {
@Override
public void transform(ITestAnnotation annotation, Class testClass,
Constructor testConstructor, Method testMethod) {
annotation.setRetryAnalyzer(RetryAnalyzer.class);
}
}Example
Register RetryTransformer as a listener in testng.xml. A retried test that passes shows as skipped + passed:
mvn testExample output
Retrying placeOrderWithUpi (1/2) [WARNING] Tests run: 13, Failures: 0, Errors: 0, Skipped: 1 [INFO] BUILD SUCCESS
Simulating Retries
Example
A flaky step fails on the first two attempts and passes on the third. The retry loop works the same way as TestNG's:
import java.util.function.*;
public class Main {
static int calls = 0;
static boolean flakyPaymentStep() {
calls++;
return calls >= 3; // QA payment sandbox is slow at first
}
static boolean runWithRetry(String name, BooleanSupplier test, int maxRetries) {
for (int attempt = 0; attempt <= maxRetries; attempt++) {
boolean passed = test.getAsBoolean();
System.out.println(name + " attempt " + (attempt + 1) + ": " + (passed ? "PASS" : "FAIL"));
if (passed) return true;
}
return false;
}
public static void main(String[] args) {
boolean ok = runWithRetry("placeOrderWithUpi", Main::flakyPaymentStep, 2);
System.out.println("Final result: " + (ok ? "PASSED (flaky, needed retries)" : "FAILED"));
calls = 0;
ok = runWithRetry("placeOrderWithCard", Main::flakyPaymentStep, 1);
System.out.println("Final result: " + (ok ? "PASSED" : "FAILED after retries"));
}
}Output
placeOrderWithUpi attempt 1: FAIL placeOrderWithUpi attempt 2: FAIL placeOrderWithUpi attempt 3: PASS Final result: PASSED (flaky, needed retries) placeOrderWithCard attempt 1: FAIL placeOrderWithCard attempt 2: FAIL Final result: FAILED after retries