Skip to content

Commit db17f3c

Browse files
committedNov 23, 2021
Include all data driven tests for reporting skips
Closes #2674 We now have a new configuration parameter named “-includeAllDataDrivenTestsWhenSkipping” which when used would cause a data driven test to report All its iterations as skipped when there is a failure in its upstream dependencies.
1 parent 4c28cd6 commit db17f3c

File tree

9 files changed

+149
-7
lines changed

9 files changed

+149
-7
lines changed
 

‎CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Current
2+
Fixed: GITHUB-2674: Run onTestSkipped for each value from data provider (Krishnan Mahadevan)
23
Fixed: GITHUB-2672: Log real stacktrace when test times out. (cdalexndr)
34
Fixed: GITHUB-2669: A failed retry with ITestContext will lose the ITestContext. (Nan Liang)
45
Fixed: GITHUB-2643: assertEquals(Set,Set) now ignores ordering as it did before. (Elis Edlund)

‎testng-core/src/main/java/org/testng/CommandLineArgs.java

+9
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,13 @@ public class CommandLineArgs {
242242
description =
243243
"Comma separated fully qualified class names of listeners that should be skipped from being wired in via Service Loaders.")
244244
public Boolean overrideIncludedMethods = false;
245+
246+
public static final String INCLUDE_ALL_DATA_DRIVEN_TESTS_WHEN_SKIPPING =
247+
"-includeAllDataDrivenTestsWhenSkipping";
248+
249+
@Parameter(
250+
names = INCLUDE_ALL_DATA_DRIVEN_TESTS_WHEN_SKIPPING,
251+
description =
252+
"Should TestNG report all iterations of a data driven test as individual skips, in-case of upstream failures.")
253+
public Boolean includeAllDataDrivenTestsWhenSkipping = false;
245254
}

‎testng-core/src/main/java/org/testng/TestNG.java

+13
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,14 @@ public void addMethodSelector(XmlMethodSelector selector) {
582582
m_selectors.add(selector);
583583
}
584584

585+
public void setReportAllDataDrivenTestsAsSkipped(boolean reportAllDataDrivenTestsAsSkipped) {
586+
this.m_configuration.setReportAllDataDrivenTestsAsSkipped(reportAllDataDrivenTestsAsSkipped);
587+
}
588+
589+
public boolean getReportAllDataDrivenTestsAsSkipped() {
590+
return this.m_configuration.getReportAllDataDrivenTestsAsSkipped();
591+
}
592+
585593
/**
586594
* Set the suites file names to be run by this TestNG object. This method tries to load and parse
587595
* the specified TestNG suite xml files. If a file is missing, it is ignored.
@@ -1404,6 +1412,7 @@ public static TestNG privateMain(String[] argv, ITestListener listener) {
14041412
* @param cla The command line parameters
14051413
*/
14061414
protected void configure(CommandLineArgs cla) {
1415+
setReportAllDataDrivenTestsAsSkipped(cla.includeAllDataDrivenTestsWhenSkipping);
14071416
if (cla.verbose != null) {
14081417
setVerbose(cla.verbose);
14091418
}
@@ -1613,6 +1622,10 @@ public void configure(Map cmdLineArgs) {
16131622
result.xmlPathInJar = (String) cmdLineArgs.get(CommandLineArgs.XML_PATH_IN_JAR);
16141623
result.junit = (Boolean) cmdLineArgs.get(CommandLineArgs.JUNIT);
16151624
result.mixed = (Boolean) cmdLineArgs.get(CommandLineArgs.MIXED);
1625+
Object tmpValue = cmdLineArgs.get(CommandLineArgs.INCLUDE_ALL_DATA_DRIVEN_TESTS_WHEN_SKIPPING);
1626+
if (tmpValue != null) {
1627+
result.includeAllDataDrivenTestsWhenSkipping = Boolean.parseBoolean(tmpValue.toString());
1628+
}
16161629
result.skipFailedInvocationCounts =
16171630
(Boolean) cmdLineArgs.get(CommandLineArgs.SKIP_FAILED_INVOCATION_COUNTS);
16181631
result.failIfAllTestsSkipped =

‎testng-core/src/main/java/org/testng/internal/Configuration.java

+12
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public class Configuration implements IConfiguration {
3333
private IInjectorFactory injectorFactory = new GuiceBackedInjectorFactory();
3434
private boolean overrideIncludedMethods = false;
3535

36+
private boolean includeAllDataDrivenTestsWhenSkipping;
37+
3638
public Configuration() {
3739
init(new JDK15AnnotationFinder(new DefaultAnnotationTransformer()));
3840
}
@@ -144,4 +146,14 @@ public boolean getOverrideIncludedMethods() {
144146
public void setOverrideIncludedMethods(boolean overrideIncludedMethods) {
145147
this.overrideIncludedMethods = overrideIncludedMethods;
146148
}
149+
150+
@Override
151+
public void setReportAllDataDrivenTestsAsSkipped(boolean reportAllDataDrivenTestsAsSkipped) {
152+
this.includeAllDataDrivenTestsWhenSkipping = reportAllDataDrivenTestsAsSkipped;
153+
}
154+
155+
@Override
156+
public boolean getReportAllDataDrivenTestsAsSkipped() {
157+
return this.includeAllDataDrivenTestsWhenSkipping;
158+
}
147159
}

‎testng-core/src/main/java/org/testng/internal/IConfiguration.java

+6
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,10 @@ default boolean addExecutionListenerIfAbsent(IExecutionListener l) {
4949
boolean getOverrideIncludedMethods();
5050

5151
void setOverrideIncludedMethods(boolean overrideIncludedMethods);
52+
53+
default void setReportAllDataDrivenTestsAsSkipped(boolean reportAllDataDrivenTestsAsSkipped) {}
54+
55+
default boolean getReportAllDataDrivenTestsAsSkipped() {
56+
return false;
57+
}
5258
}

‎testng-core/src/main/java/org/testng/internal/invokers/TestInvoker.java

+46-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import java.lang.reflect.InvocationTargetException;
99
import java.lang.reflect.Method;
10+
import java.util.ArrayList;
1011
import java.util.Collection;
1112
import java.util.Collections;
1213
import java.util.Iterator;
@@ -16,6 +17,7 @@
1617
import java.util.Optional;
1718
import java.util.Set;
1819
import java.util.concurrent.atomic.AtomicInteger;
20+
import java.util.function.Consumer;
1921
import java.util.stream.Collectors;
2022
import org.testng.DataProviderHolder;
2123
import org.testng.DataProviderInvocationException;
@@ -37,6 +39,7 @@
3739
import org.testng.SuiteRunner;
3840
import org.testng.TestException;
3941
import org.testng.TestNGException;
42+
import org.testng.collections.CollectionUtils;
4043
import org.testng.collections.Lists;
4144
import org.testng.collections.Maps;
4245
import org.testng.collections.Sets;
@@ -104,12 +107,48 @@ public List<ITestResult> invokeTestMethods(
104107
//
105108
// Not okToProceed. Test is being skipped
106109
//
107-
ITestResult result =
108-
registerSkippedTestResult(
109-
testMethod, System.currentTimeMillis(), new Throwable(okToProceed));
110-
m_notifier.addSkippedTest(testMethod, result);
111-
InvokedMethod invokedMethod = new InvokedMethod(System.currentTimeMillis(), result);
112-
invokeListenersForSkippedTestResult(result, invokedMethod);
110+
List<ITestResult> results = new ArrayList<>();
111+
Consumer<ITestResult> resultProcessor =
112+
result -> {
113+
m_notifier.addSkippedTest(testMethod, result);
114+
InvokedMethod invokedMethod = new InvokedMethod(System.currentTimeMillis(), result);
115+
invokeListenersForSkippedTestResult(result, invokedMethod);
116+
};
117+
boolean reportAllDataDrivenTestsAsSkipped =
118+
m_configuration.getReportAllDataDrivenTestsAsSkipped();
119+
if (reportAllDataDrivenTestsAsSkipped && testMethod.isDataDriven()) {
120+
ParameterHandler handler =
121+
new ParameterHandler(
122+
m_configuration.getObjectFactory(),
123+
annotationFinder(),
124+
buildDataProviderHolder(),
125+
1);
126+
127+
ParameterBag bag =
128+
handler.createParameters(
129+
testMethod, Maps.newHashMap(), Maps.newHashMap(), context, instance);
130+
Iterator<Object[]> allParamValues = Objects.requireNonNull(bag.parameterHolder).parameters;
131+
Iterable<Object[]> allParameterValues = CollectionUtils.asIterable(allParamValues);
132+
for (Object[] next : allParameterValues) {
133+
if (next == null) {
134+
continue;
135+
}
136+
Method m = testMethod.getConstructorOrMethod().getMethod();
137+
Object[] parameterValues = Parameters.injectParameters(next, m, context);
138+
ITestResult result =
139+
registerSkippedTestResult(
140+
testMethod, System.currentTimeMillis(), new Throwable(okToProceed));
141+
result.setParameters(parameterValues);
142+
resultProcessor.accept(result);
143+
results.add(result);
144+
}
145+
} else {
146+
ITestResult result =
147+
registerSkippedTestResult(
148+
testMethod, System.currentTimeMillis(), new Throwable(okToProceed));
149+
resultProcessor.accept(result);
150+
results.add(result);
151+
}
113152
testMethod.incrementCurrentInvocationCount();
114153
GroupConfigMethodArguments args =
115154
new Builder()
@@ -119,7 +158,7 @@ public List<ITestResult> invokeTestMethods(
119158
.withParameters(parameters)
120159
.build();
121160
this.invoker.invokeAfterGroupsConfigurations(args);
122-
return Collections.singletonList(result);
161+
return Collections.unmodifiableList(results);
123162
}
124163

125164
// For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread.

‎testng-core/src/test/java/test/skip/ReasonForSkipTest.java

+28
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
import java.util.Arrays;
77
import java.util.Map;
8+
import org.testng.CommandLineArgs;
89
import org.testng.ITestResult;
910
import org.testng.TestNG;
1011
import org.testng.annotations.Test;
1112
import org.testng.collections.Maps;
1213
import org.testng.xml.XmlSuite;
14+
import test.InvokedMethodNameListener;
1315
import test.SimpleBaseTest;
1416
import test.skip.github1967.TestClassSample;
17+
import test.skip.issue2674.ConfigAwareTestNG;
1518

1619
public class ReasonForSkipTest extends SimpleBaseTest {
1720

@@ -103,6 +106,31 @@ public void testEnsureTestStatusIsSetProperlyForSkippedTests() {
103106
assertThat(actual).containsAllEntriesOf(expected);
104107
}
105108

109+
@Test(description = "GITHUB-2674")
110+
public void ensureUpstreamFailuresTriggerSkipsForAllDataProviderValues() {
111+
TestNG testng = create(test.skip.issue2674.TestClassSample.class);
112+
testng.setReportAllDataDrivenTestsAsSkipped(true);
113+
InvokedMethodNameListener listener = new InvokedMethodNameListener();
114+
testng.addListener(listener);
115+
testng.run();
116+
assertThat(listener.getSkippedMethodNames())
117+
.containsExactly("test2(iPhone,13)", "test2(iPhone-Pro,12)");
118+
}
119+
120+
@Test(description = "GITHUB-2674")
121+
public void ensureUpstreamFailuresTriggerSkipsForAllDataProviderValuesViaCmdLineArgs() {
122+
CommandLineArgs cli = new CommandLineArgs();
123+
cli.includeAllDataDrivenTestsWhenSkipping = true;
124+
ConfigAwareTestNG testng = new ConfigAwareTestNG();
125+
testng.setTestClasses(new Class<?>[] {test.skip.issue2674.TestClassSample.class});
126+
testng.configure(cli);
127+
InvokedMethodNameListener listener = new InvokedMethodNameListener();
128+
testng.addListener(listener);
129+
testng.run();
130+
assertThat(listener.getSkippedMethodNames())
131+
.containsExactly("test2(iPhone,13)", "test2(iPhone-Pro,12)");
132+
}
133+
106134
private static void runTest(Map<String, String> expected, Class<?>... clazz) {
107135
TestNG testng = create(clazz);
108136
ReasonReporter reporter = new ReasonReporter();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package test.skip.issue2674;
2+
3+
import org.testng.CommandLineArgs;
4+
import org.testng.TestNG;
5+
6+
public class ConfigAwareTestNG extends TestNG {
7+
8+
@Override
9+
public void configure(CommandLineArgs cla) {
10+
super.configure(cla);
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package test.skip.issue2674;
2+
3+
import org.testng.Assert;
4+
import org.testng.annotations.DataProvider;
5+
import org.testng.annotations.Test;
6+
7+
public class TestClassSample {
8+
@Test
9+
void test1() {
10+
Assert.fail();
11+
}
12+
13+
@Test(
14+
dataProvider = "items",
15+
dependsOnMethods = {"test1"})
16+
void test2(String model, int variant) {}
17+
18+
@DataProvider(name = "items")
19+
Object[][] items() {
20+
return new Object[][] {{"iPhone", 13}, {"iPhone-Pro", 12}};
21+
}
22+
}

0 commit comments

Comments
 (0)