I have successfully implemented conditional retry logic for TestNG DataProviders using IDataProviderListener and IRetryDataProvider interfaces (as described in this answer).
However, this approach requires manually adding retryUsing = DataProviderRetryDecider.class to every @DataProvider annotation:
@DataProvider(name = "testData", retryUsing = DataProviderRetryDecider.class)
public Object[][] testData() {
// Data provider implementation
}
The Problem:
In a large codebase with 500+ @DataProvider annotations across our functional tests, this creates significant maintenance burden:
- Must manually add
retryUsingparameter to every DataProvider - New DataProviders require manual configuration
- Scattered configuration across the codebase
- Difficult to update retry logic globally
Important Context:
We have already registered our DataProviderRetryDecider as a listener in our TestNG XML suite file:
However, this listener registration alone is not sufficient. Our DataProviderRetryDecider implements two interfaces:
IDataProviderListener- captures DataProvider failures (works via listener registration)IRetryDataProvider- makes retry decisions (does NOT work via listener registration)
The IRetryDataProvider interface cannot be registered as a listener, so its retry() method will not be invoked unless we explicitly specify retryUsing = DataProviderRetryDecider.class in each @DataProvider annotation. This is why we need the manual configuration on every DataProvider.
What I Want:
Automatically inject retry logic into ALL @DataProvider annotations at runtime without manual configuration, so DataProviders can be written simply as:
@DataProvider(name = "testData")
public Object[][] testData() {
// Retry logic automatically applied
}
Question:
Is there an alternate, scalable way to apply our custom DataProviderRetryDecider to every DataProvider across our test codebase without manually adding retryUsing parameters to each annotation?
Environment:
- TestNG 7.x
- Java 11+