Skip to content

Commit 823799c

Browse files
committed
Allow data providers to be non cacheable
Closes #3041 We can now configure TestNG to enable/disable caching of test data produced by a data provider when TestNG is retrying a failed test method using the attribute “cacheDataForTestRetries” on the “@dataProvider” annotation. Below is a sample, which forces TestNG to re-invoke the data provider when a test method fails and it needs to be retried. ``` @dataProvider(name = "dp", cacheDataForTestRetries = false) public Object[][] getData() { return new Object[][] {{1}, {2}}; } ```
1 parent 2cc332d commit 823799c

File tree

11 files changed

+114
-1
lines changed

11 files changed

+114
-1
lines changed

Diff for: CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Current (7.10.0)
2+
Fixed: GITHUB-3041: TestNG 7.x DataProvider works in opposite to TestNG 6.x when retrying tests. (Krishnan Mahadevan)
23
Fixed: GITHUB-3066: How to dynamically adjust the number of TestNG threads after IExecutorFactory is deprecated? (Krishnan Mahadevan)
34
New: GITHUB-2874: Allow users to define ordering for TestNG listeners (Krishnan Mahadevan)
45
Fixed: GITHUB-3033: Moved ant support under own repository https://github.com/testng-team/testng-ant (Julien Herr)

Diff for: testng-core-api/src/main/java/org/testng/IDataProviderMethod.java

+8
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,12 @@ default boolean propagateFailureAsTestFailure() {
3838
default Class<? extends IRetryDataProvider> retryUsing() {
3939
return IRetryDataProvider.DisableDataProviderRetries.class;
4040
}
41+
42+
/**
43+
* @return - <code>true</code> if TestNG should use data returned by the original data provider
44+
* invocation, when a test method fails and is configured to be retried.
45+
*/
46+
default boolean cacheDataForTestRetries() {
47+
return true;
48+
}
4149
}

Diff for: testng-core-api/src/main/java/org/testng/annotations/DataProvider.java

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@
5757
*/
5858
boolean propagateFailureAsTestFailure() default false;
5959

60+
/**
61+
* @return - <code>true</code> if TestNG should use data returned by the original data provider
62+
* invocation, when a test method fails and is configured to be retried.
63+
*/
64+
boolean cacheDataForTestRetries() default true;
65+
6066
/**
6167
* @return - An Class which implements {@link IRetryDataProvider} and which can be used to retry a
6268
* data provider.

Diff for: testng-core-api/src/main/java/org/testng/annotations/IDataProviderAnnotation.java

+12
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,16 @@ public interface IDataProviderAnnotation extends IAnnotation {
4040
* data provider.
4141
*/
4242
Class<? extends IRetryDataProvider> retryUsing();
43+
44+
/**
45+
* @param cache - when set to <code>true</code>, TestNG does not invoke the data provider again
46+
* when retrying failed tests using a retry analyzer.
47+
*/
48+
void cacheDataForTestRetries(boolean cache);
49+
50+
/**
51+
* @return - <code>true</code> if TestNG should use data returned by the original data provider
52+
* invocation, when a test method fails and is configured to be retried.
53+
*/
54+
boolean isCacheDataForTestRetries();
4355
}

Diff for: testng-core/src/main/java/org/testng/internal/DataProviderMethod.java

+5
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,9 @@ public boolean propagateFailureAsTestFailure() {
5353
public Class<? extends IRetryDataProvider> retryUsing() {
5454
return annotation.retryUsing();
5555
}
56+
57+
@Override
58+
public boolean cacheDataForTestRetries() {
59+
return annotation.isCacheDataForTestRetries();
60+
}
5661
}

Diff for: testng-core/src/main/java/org/testng/internal/Parameters.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ private static void checkParameterTypes(
442442
throw new TestNGException(
443443
errPrefix
444444
+ ".\nFor more information on native dependency injection please refer to "
445-
+ "https://testng.org/doc/documentation-main.html#native-dependency-injection");
445+
+ "https://testng.org/#_dependency_injection");
446446
}
447447
}
448448

Diff for: testng-core/src/main/java/org/testng/internal/annotations/DataProviderAnnotation.java

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public class DataProviderAnnotation extends BaseAnnotation implements IDataProvi
1313
private boolean m_bubbleUpFailures = false;
1414
private Class<? extends IRetryDataProvider> retryUsing;
1515

16+
private boolean cachedDataForTestRetries = true;
17+
1618
@Override
1719
public boolean isParallel() {
1820
return m_parallel;
@@ -62,4 +64,13 @@ public void setRetryUsing(Class<? extends IRetryDataProvider> retry) {
6264
public Class<? extends IRetryDataProvider> retryUsing() {
6365
return retryUsing;
6466
}
67+
68+
public void cacheDataForTestRetries(boolean cache) {
69+
this.cachedDataForTestRetries = cache;
70+
}
71+
72+
@Override
73+
public boolean isCacheDataForTestRetries() {
74+
return cachedDataForTestRetries;
75+
}
6576
}

Diff for: testng-core/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java

+1
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ private IAnnotation createDataProviderTag(Method method, Annotation a) {
483483
result.propagateFailureAsTestFailure();
484484
}
485485
result.setRetryUsing(c.retryUsing());
486+
result.cacheDataForTestRetries(c.cacheDataForTestRetries());
486487
return result;
487488
}
488489

Diff for: testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java

+19
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.testng.DataProviderHolder;
2424
import org.testng.IClassListener;
2525
import org.testng.IDataProviderListener;
26+
import org.testng.IDataProviderMethod;
2627
import org.testng.IHookable;
2728
import org.testng.IInvokedMethod;
2829
import org.testng.IInvokedMethodListener;
@@ -238,6 +239,24 @@ public FailureContext retryFailed(
238239
failure.representsRetriedMethod.set(true);
239240
do {
240241
failure.instances = Lists.newArrayList();
242+
boolean cacheData =
243+
Optional.ofNullable(arguments.getTestMethod().getDataProviderMethod())
244+
.map(IDataProviderMethod::cacheDataForTestRetries)
245+
.orElse(false);
246+
if (!cacheData) {
247+
Map<String, String> allParameters = Maps.newHashMap();
248+
int verbose = testContext.getCurrentXmlTest().getVerbose();
249+
ParameterHandler handler =
250+
new ParameterHandler(
251+
m_configuration.getObjectFactory(), annotationFinder(), this.holder, verbose);
252+
253+
ParameterBag bag =
254+
handler.createParameters(
255+
arguments.getTestMethod(), arguments.getParameters(), allParameters, testContext);
256+
if (bag.hasErrors()) {
257+
continue;
258+
}
259+
}
241260
Object[] parameterValues = arguments.getParameterValues();
242261
TestMethodArguments tma =
243262
new TestMethodArguments.Builder()

Diff for: testng-core/src/test/java/test/dataprovider/DataProviderTest.java

+9
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,21 @@
5555
import test.dataprovider.issue2934.TestCaseSample.CoreListener;
5656
import test.dataprovider.issue2934.TestCaseSample.ToggleDataProvider;
5757
import test.dataprovider.issue2980.LoggingListener;
58+
import test.dataprovider.issue3041.SampleTestCase;
5859
import test.dataprovider.issue3045.DataProviderListener;
5960
import test.dataprovider.issue3045.DataProviderTestClassSample;
6061
import test.dataprovider.issue3045.DataProviderWithoutListenerTestClassSample;
6162

6263
public class DataProviderTest extends SimpleBaseTest {
6364

65+
@Test(description = "GITHUB-3041")
66+
public void ensureDataProvidersCanBeInstructedNotToCacheDataForFailedTestRetries() {
67+
TestNG testng = create(SampleTestCase.class);
68+
testng.setVerbose(2);
69+
testng.run();
70+
assertThat(SampleTestCase.invocationCount.get()).isEqualTo(2);
71+
}
72+
6473
@Test(description = "GITHUB-2819")
6574
public void testDataProviderCanBeRetriedOnFailures() {
6675
TestNG testng = create(TestClassUsingDataProviderRetrySample.class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package test.dataprovider.issue3041;
2+
3+
import java.util.Random;
4+
import java.util.concurrent.atomic.AtomicInteger;
5+
import org.testng.IRetryAnalyzer;
6+
import org.testng.ITestResult;
7+
import org.testng.annotations.DataProvider;
8+
import org.testng.annotations.Test;
9+
10+
public class SampleTestCase {
11+
12+
public static final AtomicInteger invocationCount = new AtomicInteger(0);
13+
private static final Random random = new Random();
14+
15+
@Test(dataProvider = "dp", retryAnalyzer = MyRetry.class)
16+
public void testMethod(int i) {
17+
if (invocationCount.get() != 2) {
18+
throw new RuntimeException("Failed for " + i);
19+
}
20+
}
21+
22+
@DataProvider(name = "dp", cacheDataForTestRetries = false)
23+
public Object[][] getData() {
24+
invocationCount.incrementAndGet();
25+
return new Object[][] {{next()}, {next()}};
26+
}
27+
28+
private static int next() {
29+
return random.nextInt();
30+
}
31+
32+
public static class MyRetry implements IRetryAnalyzer {
33+
34+
private final AtomicInteger counter = new AtomicInteger(1);
35+
36+
@Override
37+
public boolean retry(ITestResult result) {
38+
return counter.getAndIncrement() != 2;
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)