builder() //
41 | .addClassContainerSelectorResolver(new IsTestNGTestClass()) //
42 | .addSelectorResolver(ctx -> new TestNGSelectorResolver(ctx.getClassNameFilter(),
43 | ctx.getEngineDescriptor().getTestDescriptorFactory())) //
44 | .build();
45 |
46 | /**
47 | * Create a new instance (typically called by the JUnit Platform via ServiceLoader).
48 | */
49 | public TestNGTestEngine() {
50 | }
51 |
52 | @Override
53 | public String getId() {
54 | return "testng";
55 | }
56 |
57 | /**
58 | * Discover TestNG tests based on the supplied {@linkplain EngineDiscoveryRequest request}.
59 | *
60 | * Supports the following {@linkplain org.junit.platform.engine.DiscoverySelector selectors}:
61 | *
62 | * {@link org.junit.platform.engine.discovery.ClasspathRootSelector}
63 | * {@link org.junit.platform.engine.discovery.ClassSelector}
64 | * {@link org.junit.platform.engine.discovery.MethodSelector}
65 | * {@link org.junit.platform.engine.discovery.ModuleSelector}
66 | * {@link org.junit.platform.engine.discovery.PackageSelector}
67 | * {@link org.junit.platform.engine.discovery.UniqueIdSelector}
68 | *
69 | *
70 | * Custom test suites specified via {@code testng.xml} files are not supported.
71 | *
72 | * Supports the following {@linkplain org.junit.platform.engine.Filter filters}:
73 | *
74 | * {@link org.junit.platform.engine.discovery.ClassNameFilter}
75 | * {@link org.junit.platform.engine.discovery.PackageNameFilter}
76 | * Any post-discovery filter, e.g. for included/excluded tags
77 | *
78 | *
79 | * The implementation collects a list of potential test classes and method names and uses
80 | * TestNG's dry-run mode to determine which of them are TestNG test classes and methods. Since
81 | * TestNG can only run either classes or methods, it will be executed twice in the edge case
82 | * that class and method selectors are part of the discovery request.
83 | */
84 | @Override
85 | public TestDescriptor discover(EngineDiscoveryRequest request, UniqueId uniqueId) {
86 | TestNGEngineDescriptor engineDescriptor = new TestNGEngineDescriptor(uniqueId);
87 |
88 | DISCOVERY_REQUEST_RESOLVER.resolve(request, engineDescriptor);
89 | Class>[] testClasses = engineDescriptor.getTestClasses();
90 | List methodNames = engineDescriptor.getQualifiedMethodNames();
91 |
92 | ConfigurationParameters configurationParameters = request.getConfigurationParameters();
93 | DiscoveryListener listener = new DiscoveryListener(request, engineDescriptor);
94 |
95 | if (testClasses.length > 0) {
96 | withTemporarySystemProperty(TESTNG_MODE_DRYRUN, "true",
97 | () -> configureAndRun(configurationParameters, listener, testClasses(testClasses), Phase.DISCOVERY));
98 | }
99 |
100 | if (!methodNames.isEmpty()) {
101 | withTemporarySystemProperty(TESTNG_MODE_DRYRUN, "true",
102 | () -> configureAndRun(configurationParameters, listener, testMethods(methodNames), Phase.DISCOVERY));
103 | }
104 |
105 | listener.finalizeDiscovery();
106 |
107 | return engineDescriptor;
108 | }
109 |
110 | /**
111 | * Execute the previously discovered TestNG tests in the supplied {@linkplain ExecutionRequest request}.
112 | *
113 | * Supports the following configuration parameters:
114 | *
Execution
115 | *
116 | * {@code testng.allowReturnValues} (file path)
117 | * whether methods annotated with {@code @Test} that have return values should be considered test methods (default: {@code false})
118 | *
119 | * {@code testng.dataProviderThreadCount} (file path)
120 | * maximum number of threads to use for running data providers in parallel, if enabled via {@link DataProvider#parallel()} (default: {@code 10})
121 | *
122 | * {@code testng.parallel} (methods|tests|classes|instances|none)
123 | * TestNG's parallel execution mode for running tests in separate threads (default: {@code "none"})
124 | *
125 | * {@code testng.preserveOrder} (boolean)
126 | * whether classes and methods should be run in a predictable order (default: {@code true})
127 | *
128 | * {@code testng.threadCount} (boolean)
129 | * maximum number of threads for running tests in parallel, if enabled via {@code testng.parallel} (default: {@code 5})
130 | *
131 | * Reporting
132 | *
133 | * {@code testng.listeners} (comma-separated list of fully-qualified class names)
134 | * custom listeners that should be registered when executing tests (default: {@code ""})
135 | *
136 | * {@code testng.outputDirectory} (file path)
137 | * the output directory for reports (default: {@code "test-output"})
138 | *
139 | * {@code testng.useDefaultListeners} (boolean)
140 | * whether TestNG's default report generating listeners should be used (default: {@code false})
141 | *
142 | * {@code testng.verbose} (integer)
143 | * TestNG's level of verbosity (default: {@code 0})
144 | *
145 | *
146 | * The implementation configures TestNG as if the discovered methods were specified on the
147 | * command line.
148 | *
149 | * Data providers test methods are reported as a nested structure, i.e. individual invocations
150 | * are reported underneath the test methods along with their parameters:
151 | *
152 | * └─ TestNG ✔
153 | * └─ DataProviderMethodTestCase ✔
154 | * └─ test(java.lang.String) ✔
155 | * ├─ [0] a ✔
156 | * └─ [1] b ✔
157 | *
158 | */
159 | @Override
160 | public void execute(ExecutionRequest request) {
161 | EngineExecutionListener listener = request.getEngineExecutionListener();
162 | TestNGEngineDescriptor engineDescriptor = (TestNGEngineDescriptor) request.getRootTestDescriptor();
163 | listener.executionStarted(engineDescriptor);
164 | engineDescriptor.prepareExecution();
165 | ExecutionListener executionListener = new ExecutionListener(listener, engineDescriptor);
166 | List methodNames = engineDescriptor.getQualifiedMethodNames();
167 | if (!methodNames.isEmpty()) {
168 | configureAndRun(request.getConfigurationParameters(), executionListener, testMethods(methodNames),
169 | Phase.EXECUTION);
170 | }
171 | listener.executionFinished(engineDescriptor, executionListener.toEngineResult());
172 | }
173 |
174 | private static void configureAndRun(ConfigurationParameters configurationParameters, ITestNGListener listener,
175 | Configurer... configurers) {
176 | CommandLineArgs commandLineArgs = new CommandLineArgs();
177 | for (Configurer configurer : configurers) {
178 | configurer.configure(commandLineArgs, configurationParameters);
179 | }
180 | configurationParameters.get("testng.groups").ifPresent(it -> commandLineArgs.groups = it);
181 | configurationParameters.get("testng.excludedGroups").ifPresent(it -> commandLineArgs.excludedGroups = it);
182 | ConfigurableTestNG testNG = new ConfigurableTestNG();
183 | testNG.configure(commandLineArgs);
184 | for (Configurer configurer : configurers) {
185 | configurer.configure(testNG, configurationParameters);
186 | }
187 | testNG.addListener(LoggingListener.INSTANCE);
188 | testNG.addListener(new ConfiguringListener(configurationParameters));
189 | testNG.addListener(listener);
190 | testNG.run();
191 | }
192 |
193 | @SuppressWarnings("SameParameterValue")
194 | private static void withTemporarySystemProperty(String key, String value, Runnable action) {
195 | String originalValue = System.getProperty(key);
196 | System.setProperty(key, value);
197 | try {
198 | action.run();
199 | }
200 | finally {
201 | if (originalValue == null) {
202 | System.getProperties().remove(key);
203 | }
204 | else {
205 | System.setProperty(key, originalValue);
206 | }
207 | }
208 | }
209 |
210 | interface Configurer {
211 |
212 | static Configurer testClasses(Class>[] testClasses) {
213 | return new Configurer() {
214 | @Override
215 | public void configure(TestNG testNG, ConfigurationParameters config) {
216 | testNG.setTestClasses(testClasses);
217 | }
218 | };
219 | }
220 |
221 | static Configurer testMethods(List methodNames) {
222 | return new Configurer() {
223 | @Override
224 | public void configure(CommandLineArgs commandLineArgs, ConfigurationParameters config) {
225 | commandLineArgs.commandLineMethods = methodNames;
226 | }
227 | };
228 | }
229 |
230 | default void configure(TestNG testNG, ConfigurationParameters config) {
231 | }
232 |
233 | default void configure(CommandLineArgs commandLineArgs, ConfigurationParameters config) {
234 | }
235 |
236 | }
237 |
238 | enum Phase implements Configurer {
239 |
240 | DISCOVERY {
241 | @Override
242 | public void configure(TestNG testNG, ConfigurationParameters config) {
243 | testNG.setVerbose(0);
244 | testNG.setUseDefaultListeners(false);
245 | }
246 | },
247 |
248 | EXECUTION {
249 | @Override
250 | public void configure(TestNG testNG, ConfigurationParameters config) {
251 | testNG.setVerbose(config.get("testng.verbose", Integer::valueOf).orElse(0));
252 | testNG.setUseDefaultListeners(config.getBoolean("testng.useDefaultListeners").orElse(false));
253 | config.get("testng.outputDirectory") //
254 | .ifPresent(testNG::setOutputDirectory);
255 | config.getBoolean("testng.preserveOrder") //
256 | .ifPresent(testNG::setPreserveOrder);
257 | config.get("testng.parallel", ParallelMode::getValidParallel) //
258 | .ifPresent(testNG::setParallel);
259 | config.get("testng.threadCount", Integer::parseInt) //
260 | .ifPresent(testNG::setThreadCount);
261 | config.get("testng.dataProviderThreadCount", Integer::parseInt) //
262 | .ifPresent(testNG::setDataProviderThreadCount);
263 | }
264 |
265 | @Override
266 | public void configure(CommandLineArgs commandLineArgs, ConfigurationParameters config) {
267 | config.get("testng.listeners") //
268 | .ifPresent(listeners -> commandLineArgs.listener = listeners);
269 | }
270 | };
271 | }
272 |
273 | /**
274 | * Needed to make {@link #configure(CommandLineArgs)} accessible.
275 | */
276 | private static class ConfigurableTestNG extends TestNG {
277 | @Override
278 | protected void configure(CommandLineArgs cla) {
279 | super.configure(cla);
280 | }
281 | }
282 | }
283 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/org.junit.platform.engine.TestEngine:
--------------------------------------------------------------------------------
1 | org.junit.support.testng.engine.TestNGTestEngine
2 |
--------------------------------------------------------------------------------
/src/module/java/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | /**
12 | * Provides the TestNG {@linkplain org.junit.platform.engine.TestEngine} implementation.
13 | *
14 | * @since 1.0
15 | * @provides org.junit.platform.engine.TestEngine
16 | * @see org.junit.support.testng.engine.TestNGTestEngine
17 | */
18 | module org.junit.support.testng.engine {
19 | requires org.junit.platform.engine;
20 | requires org.testng;
21 | requires java.logging;
22 | provides org.junit.platform.engine.TestEngine with org.junit.support.testng.engine.TestNGTestEngine;
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/AbstractIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static java.util.function.Predicate.isEqual;
14 | import static org.assertj.core.api.Assertions.allOf;
15 | import static org.junit.platform.commons.util.FunctionUtils.where;
16 | import static org.junit.platform.engine.TestExecutionResult.Status.ABORTED;
17 | import static org.junit.platform.testkit.engine.Event.byTestDescriptor;
18 | import static org.junit.platform.testkit.engine.EventConditions.container;
19 | import static org.junit.platform.testkit.engine.EventConditions.displayName;
20 | import static org.junit.platform.testkit.engine.EventConditions.event;
21 | import static org.junit.platform.testkit.engine.EventConditions.finished;
22 | import static org.junit.platform.testkit.engine.EventConditions.uniqueIdSubstring;
23 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.status;
24 |
25 | import java.nio.file.Path;
26 | import java.util.Optional;
27 |
28 | import org.assertj.core.api.Condition;
29 | import org.junit.jupiter.api.io.TempDir;
30 | import org.junit.platform.engine.TestDescriptor;
31 | import org.junit.platform.engine.TestExecutionResult;
32 | import org.junit.platform.testkit.engine.EngineTestKit;
33 | import org.junit.platform.testkit.engine.Event;
34 |
35 | abstract class AbstractIntegrationTests {
36 |
37 | @TempDir
38 | Path tempDir;
39 |
40 | EngineTestKit.Builder testNGEngine() {
41 | return EngineTestKit.engine("testng") //
42 | .configurationParameter("testng.verbose", "10") //
43 | .configurationParameter("testng.useDefaultListeners", "false") //
44 | .configurationParameter("testng.outputDirectory", tempDir.toString());
45 | }
46 |
47 | static Condition testClass(Class> testClass) {
48 | return container(event(displayName(testClass.getSimpleName()), uniqueIdSubstring(testClass.getName()),
49 | legacyReportingName(testClass.getName())));
50 | }
51 |
52 | static Condition legacyReportingName(String legacyReportingName) {
53 | return new Condition<>(
54 | byTestDescriptor(where(TestDescriptor::getLegacyReportingName, isEqual(legacyReportingName))),
55 | "descriptor with legacy reporting name '%s'", legacyReportingName);
56 | }
57 |
58 | static Condition abortedWithoutReason() {
59 | return finished(allOf(status(ABORTED), emptyThrowable()));
60 | }
61 |
62 | static Condition emptyThrowable() {
63 | return new Condition<>(where(TestExecutionResult::getThrowable, Optional::isEmpty), "throwable is empty");
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/ConfigurationMethodIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
15 | import static org.junit.platform.testkit.engine.EventConditions.abortedWithReason;
16 | import static org.junit.platform.testkit.engine.EventConditions.engine;
17 | import static org.junit.platform.testkit.engine.EventConditions.event;
18 | import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
19 | import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
20 | import static org.junit.platform.testkit.engine.EventConditions.started;
21 | import static org.junit.platform.testkit.engine.EventConditions.test;
22 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
23 |
24 | import example.configuration.methods.FailingAfterClassConfigurationMethodTestCase;
25 | import example.configuration.methods.FailingAfterMethodConfigurationMethodTestCase;
26 | import example.configuration.methods.FailingAfterSuiteConfigurationMethodTestCase;
27 | import example.configuration.methods.FailingAfterTestConfigurationMethodTestCase;
28 | import example.configuration.methods.FailingBeforeClassConfigurationMethodTestCase;
29 | import example.configuration.methods.FailingBeforeMethodConfigurationMethodTestCase;
30 | import example.configuration.methods.FailingBeforeSuiteConfigurationMethodTestCase;
31 | import example.configuration.methods.FailingBeforeTestConfigurationMethodTestCase;
32 | import example.configuration.methods.GroupsConfigurationMethodsTestCase;
33 |
34 | import org.junit.jupiter.api.Test;
35 | import org.junit.jupiter.params.ParameterizedTest;
36 | import org.junit.jupiter.params.provider.ValueSource;
37 |
38 | class ConfigurationMethodIntegrationTests extends AbstractIntegrationTests {
39 |
40 | @Test
41 | void reportsFailureFromBeforeClassMethod() {
42 | var results = testNGEngine().selectors(
43 | selectClass(FailingBeforeClassConfigurationMethodTestCase.class)).execute();
44 |
45 | results.allEvents().assertEventsMatchLooselyInOrder( //
46 | event(testClass(FailingBeforeClassConfigurationMethodTestCase.class), started()), //
47 | event(testClass(FailingBeforeClassConfigurationMethodTestCase.class),
48 | finishedWithFailure(message("boom"))));
49 | }
50 |
51 | @Test
52 | void reportsFailureFromBeforeMethodConfigurationMethodAsAbortedWithThrowable() {
53 | var testClass = FailingBeforeMethodConfigurationMethodTestCase.class;
54 |
55 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
56 |
57 | results.allEvents().assertEventsMatchLooselyInOrder( //
58 | event(testClass(testClass), started()), //
59 | event(test("method:a()"), started()), //
60 | event(test("method:a()"), finishedSuccessfully()), //
61 | event(test("method:b()"), started()), //
62 | event(test("method:b()"), abortedWithReason(message("boom"))), //
63 | event(testClass(testClass), finishedWithFailure(message("boom"))));
64 | }
65 |
66 | @ParameterizedTest
67 | @ValueSource(classes = { FailingBeforeTestConfigurationMethodTestCase.class,
68 | FailingBeforeSuiteConfigurationMethodTestCase.class })
69 | void reportsFailureFromEarlyEngineLevelConfigurationMethodAsAborted(Class> testClass) {
70 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
71 |
72 | results.allEvents().debug().assertEventsMatchExactly( //
73 | event(engine(), started()), //
74 | event(testClass(testClass), started()), //
75 | event(test("method:test()"), started()), //
76 | event(test("method:test()"), abortedWithReason(message("boom"))), //
77 | event(testClass(testClass), abortedWithoutReason()), //
78 | event(engine(), finishedWithFailure(message("boom"))));
79 | }
80 |
81 | @Test
82 | void reportsFailureFromAfterMethodConfigurationMethodAsClassLevelFailure() {
83 | var testClass = FailingAfterMethodConfigurationMethodTestCase.class;
84 |
85 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
86 |
87 | results.allEvents().assertEventsMatchLooselyInOrder( //
88 | event(testClass(testClass), started()), //
89 | event(test("method:test()"), started()), //
90 | event(test("method:test()"), finishedSuccessfully()), //
91 | event(testClass(testClass), finishedWithFailure(message("boom"))));
92 | }
93 |
94 | @ParameterizedTest
95 | @ValueSource(classes = { FailingAfterClassConfigurationMethodTestCase.class,
96 | FailingAfterTestConfigurationMethodTestCase.class, FailingAfterSuiteConfigurationMethodTestCase.class })
97 | void reportsFailureFromLateEngineLevelConfigurationMethodAsEngineLevelFailure(Class> testClass) {
98 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
99 |
100 | results.allEvents().assertEventsMatchExactly( //
101 | event(engine(), started()), //
102 | event(testClass(testClass), started()), //
103 | event(test("method:test()"), started()), //
104 | event(test("method:test()"), finishedSuccessfully()), //
105 | event(testClass(testClass), finishedSuccessfully()), //
106 | event(engine(), finishedWithFailure(message("boom"))));
107 | }
108 |
109 | @Test
110 | void runsGroupsIncludingConfigurationMethods() {
111 | Class> testClass = GroupsConfigurationMethodsTestCase.class;
112 | GroupsConfigurationMethodsTestCase.EVENTS.clear();
113 |
114 | var results = testNGEngine() //
115 | .selectors(selectClass(testClass)) //
116 | .configurationParameter("testng.groups", "group1") //
117 | .configurationParameter("testng.excludedGroups", "group2") //
118 | .execute();
119 |
120 | results.allEvents().assertEventsMatchExactly( //
121 | event(engine(), started()), //
122 | event(testClass(testClass), started()), //
123 | event(test("method:testGroup1()"), started()), //
124 | event(test("method:testGroup1()"), finishedSuccessfully()), //
125 | event(testClass(testClass), finishedSuccessfully()), //
126 | event(engine(), finishedSuccessfully()));
127 |
128 | assertThat(GroupsConfigurationMethodsTestCase.EVENTS) //
129 | .containsExactly("beforeGroup1", "testGroup1", "afterGroup1");
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/ConfigurationParametersIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
15 | import static org.junit.platform.testkit.engine.EventConditions.event;
16 | import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
17 | import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
18 | import static org.junit.platform.testkit.engine.EventConditions.started;
19 | import static org.junit.platform.testkit.engine.EventConditions.test;
20 |
21 | import example.configuration.parameters.DataProviderThreadCountTestCase;
22 | import example.configuration.parameters.InvocationTrackingListener;
23 | import example.configuration.parameters.ParallelMethodsTestCase;
24 | import example.configuration.parameters.PreserveOrderTestCase;
25 | import example.configuration.parameters.ReturnValuesTestCase;
26 | import example.configuration.parameters.SystemPropertyProvidingListener;
27 | import example.configuration.parameters.SystemPropertyReadingTestCase;
28 |
29 | import org.junit.jupiter.api.Test;
30 | import org.junit.jupiter.params.ParameterizedTest;
31 | import org.junit.jupiter.params.provider.ValueSource;
32 |
33 | class ConfigurationParametersIntegrationTests extends AbstractIntegrationTests {
34 |
35 | @Test
36 | void registersCustomListeners() {
37 | var testClass = SystemPropertyReadingTestCase.class;
38 | InvocationTrackingListener.invoked = false;
39 |
40 | var results = testNGEngine() //
41 | .selectors(selectClass(testClass)) //
42 | .configurationParameter("testng.listeners", SystemPropertyProvidingListener.class.getName() + " , "
43 | + InvocationTrackingListener.class.getName()) //
44 | .execute();
45 |
46 | assertThat(InvocationTrackingListener.invoked).isTrue();
47 | results.allEvents().assertEventsMatchLooselyInOrder( //
48 | event(testClass(testClass), started()), //
49 | event(test("method:test()"), started()), //
50 | event(test("method:test()"), finishedSuccessfully()), //
51 | event(testClass(testClass), finishedSuccessfully()));
52 | }
53 |
54 | @Test
55 | void executesTestMethodsWithReturnValuesWhenEnabledViaConfigurationParameter() {
56 | var testClass = ReturnValuesTestCase.class;
57 |
58 | var results = testNGEngine() //
59 | .selectors(selectClass(testClass)) //
60 | .configurationParameter("testng.allowReturnValues", "true") //
61 | .execute();
62 |
63 | results.allEvents().assertEventsMatchLooselyInOrder( //
64 | event(testClass(testClass), started()), //
65 | event(test("method:test()"), started()), //
66 | event(test("method:test()"), finishedSuccessfully()), //
67 | event(testClass(testClass), finishedSuccessfully()));
68 | }
69 |
70 | @ParameterizedTest
71 | @ValueSource(booleans = { true, false })
72 | void configuresPreserveOrderOnXmlTest(boolean preserveOrder) {
73 | var testClass = PreserveOrderTestCase.class;
74 |
75 | var results = testNGEngine() //
76 | .selectors(selectClass(testClass)) //
77 | .configurationParameter("testng.preserveOrder", String.valueOf(preserveOrder)) //
78 | .execute();
79 |
80 | results.allEvents().assertEventsMatchLooselyInOrder( //
81 | event(testClass(testClass), started()), //
82 | event(test("method:test(org.testng.ITestContext)"), started()), //
83 | event(test("method:test(org.testng.ITestContext)"),
84 | preserveOrder ? finishedSuccessfully() : finishedWithFailure()), //
85 | event(testClass(testClass), finishedSuccessfully()));
86 | }
87 |
88 | @Test
89 | void configuresParallelMode() {
90 | var testClass = ParallelMethodsTestCase.class;
91 |
92 | var results = testNGEngine() //
93 | .selectors(selectClass(testClass)) //
94 | .configurationParameter("testng.parallel", "methods") //
95 | .execute();
96 |
97 | results.testEvents().debug().assertStatistics(stats -> stats.succeeded(2));
98 | }
99 |
100 | @Test
101 | void configuresThreadCount() {
102 | var testClass = ParallelMethodsTestCase.class;
103 |
104 | var results = testNGEngine() //
105 | .selectors(selectClass(testClass)) //
106 | .configurationParameter("testng.parallel", "methods") //
107 | .configurationParameter("testng.threadCount", "1") //
108 | .execute();
109 |
110 | results.testEvents().debug().assertStatistics(stats -> stats.succeeded(1).failed(1));
111 | }
112 |
113 | @Test
114 | void configuresDataProviderThreadCount() {
115 | var testClass = DataProviderThreadCountTestCase.class;
116 | var numInvocations = DataProviderThreadCountTestCase.NUM_INVOCATIONS;
117 |
118 | var results = testNGEngine() //
119 | .selectors(selectClass(testClass)) //
120 | .configurationParameter("testng.dataProviderThreadCount", String.valueOf(numInvocations)) //
121 | .execute();
122 |
123 | results.testEvents().debug().assertStatistics(stats -> stats.succeeded(numInvocations));
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/DataProviderIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static java.util.function.Function.identity;
14 | import static java.util.stream.Collectors.toMap;
15 | import static org.assertj.core.api.Assertions.assertThat;
16 | import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement;
17 | import static org.junit.platform.engine.TestDescriptor.Type.CONTAINER;
18 | import static org.junit.platform.engine.TestDescriptor.Type.TEST;
19 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
20 | import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
21 | import static org.junit.platform.testkit.engine.EventConditions.abortedWithReason;
22 | import static org.junit.platform.testkit.engine.EventConditions.container;
23 | import static org.junit.platform.testkit.engine.EventConditions.displayName;
24 | import static org.junit.platform.testkit.engine.EventConditions.dynamicTestRegistered;
25 | import static org.junit.platform.testkit.engine.EventConditions.engine;
26 | import static org.junit.platform.testkit.engine.EventConditions.event;
27 | import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
28 | import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
29 | import static org.junit.platform.testkit.engine.EventConditions.started;
30 | import static org.junit.platform.testkit.engine.EventConditions.test;
31 | import static org.junit.platform.testkit.engine.EventConditions.uniqueIdSubstring;
32 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
33 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
34 | import static org.junit.support.testng.engine.TestContext.testNGVersion;
35 |
36 | import example.dataproviders.*;
37 |
38 | import org.apache.maven.artifact.versioning.ComparableVersion;
39 | import org.junit.jupiter.api.Test;
40 | import org.junit.platform.engine.TestDescriptor;
41 | import org.junit.platform.engine.UniqueId;
42 | import org.junit.platform.engine.support.descriptor.MethodSource;
43 |
44 | class DataProviderIntegrationTests extends AbstractIntegrationTests {
45 |
46 | @Test
47 | void discoversDataProviderTestMethods() {
48 | var request = request().selectors(selectClass(DataProviderMethodTestCase.class)).build();
49 |
50 | var rootDescriptor = new TestNGTestEngine().discover(request, UniqueId.forEngine("testng"));
51 |
52 | var classDescriptor = getOnlyElement(rootDescriptor.getChildren());
53 | assertThat(classDescriptor.getChildren()).hasSize(3);
54 |
55 | var methodDescriptors = classDescriptor.getChildren().stream() //
56 | .collect(toMap(TestDescriptor::getDisplayName, identity()));
57 | assertThat(methodDescriptors.keySet()).containsExactlyInAnyOrder("test", "test(java.lang.String)", "test(int)");
58 | methodDescriptors.forEach((displayName, methodDescriptor) -> {
59 | assertThat(methodDescriptor.getLegacyReportingName()).isEqualTo(displayName);
60 | assertThat(methodDescriptor.getChildren()).isEmpty();
61 | });
62 |
63 | assertThat(methodDescriptors.get("test").getType()) //
64 | .isEqualTo(TEST);
65 | assertThat(methodDescriptors.get("test").getSource()) //
66 | .contains(MethodSource.from(DataProviderMethodTestCase.class.getName(), "test", ""));
67 | assertThat(methodDescriptors.get("test").getUniqueId().getLastSegment().getValue()) //
68 | .isEqualTo("test()");
69 |
70 | assertThat(methodDescriptors.get("test(java.lang.String)").getType()) //
71 | .isEqualTo(CONTAINER);
72 | assertThat(methodDescriptors.get("test(java.lang.String)").getSource()) //
73 | .contains(
74 | MethodSource.from(DataProviderMethodTestCase.class.getName(), "test", String.class.getName()));
75 | assertThat(methodDescriptors.get("test(java.lang.String)").getUniqueId().getLastSegment().getValue()) //
76 | .isEqualTo("test(java.lang.String)");
77 |
78 | assertThat(methodDescriptors.get("test(int)").getType()) //
79 | .isEqualTo(CONTAINER);
80 | assertThat(methodDescriptors.get("test(int)").getSource()) //
81 | .contains(MethodSource.from(DataProviderMethodTestCase.class.getName(), "test", int.class.getName()));
82 | assertThat(methodDescriptors.get("test(int)").getUniqueId().getLastSegment().getValue()) //
83 | .isEqualTo("test(int)");
84 | }
85 |
86 | @Test
87 | void executesDataProviderTestMethods() {
88 | var results = testNGEngine().selectors(selectClass(DataProviderMethodTestCase.class)).execute();
89 |
90 | results.allEvents().assertEventsMatchLooselyInOrder( //
91 | event(testClass(DataProviderMethodTestCase.class), started()), //
92 | event(test("method:test()"), started()), //
93 | event(test("method:test()"), finishedWithFailure(message("parameterless"))), //
94 | event(testClass(DataProviderMethodTestCase.class), finishedSuccessfully()));
95 | results.allEvents().assertEventsMatchLooselyInOrder( //
96 | event(testClass(DataProviderMethodTestCase.class), started()), //
97 | event(container("method:test(java.lang.String)"), started()), //
98 | event(uniqueIdSubstring("method:test(java.lang.String)"), dynamicTestRegistered("invoc:0"),
99 | displayName("[0] a"), legacyReportingName("test(java.lang.String)[0]")), //
100 | event(uniqueIdSubstring("method:test(java.lang.String)"), test("invoc:0"), started()), //
101 | event(uniqueIdSubstring("method:test(java.lang.String)"), test("invoc:0"),
102 | finishedWithFailure(message("a"))), //
103 | event(uniqueIdSubstring("method:test(java.lang.String)"), dynamicTestRegistered("invoc:1"),
104 | displayName("[1] b"), legacyReportingName("test(java.lang.String)[1]")), //
105 | event(uniqueIdSubstring("method:test(java.lang.String)"), test("invoc:1"), started()), //
106 | event(uniqueIdSubstring("method:test(java.lang.String)"), test("invoc:1"),
107 | finishedWithFailure(message("b"))), //
108 | event(container("method:test(java.lang.String)"), finishedSuccessfully()), //
109 | event(testClass(DataProviderMethodTestCase.class), finishedSuccessfully()));
110 | results.allEvents().assertEventsMatchLooselyInOrder( //
111 | event(testClass(DataProviderMethodTestCase.class), started()), //
112 | event(container("method:test(int)"), started()), //
113 | event(uniqueIdSubstring("method:test(int)"), dynamicTestRegistered("invoc:0"), displayName("[0] 1"),
114 | legacyReportingName("test(int)[0]")), //
115 | event(uniqueIdSubstring("method:test(int)"), test("invoc:0"), started()), //
116 | event(uniqueIdSubstring("method:test(int)"), test("invoc:0"), finishedWithFailure(message("1"))), //
117 | event(uniqueIdSubstring("method:test(int)"), dynamicTestRegistered("invoc:1"), displayName("[1] 2"),
118 | legacyReportingName("test(int)[1]")), //
119 | event(uniqueIdSubstring("method:test(int)"), test("invoc:1"), started()), //
120 | event(uniqueIdSubstring("method:test(int)"), test("invoc:1"), finishedWithFailure(message("2"))), //
121 | event(container("method:test(int)"), finishedSuccessfully()), //
122 | event(testClass(DataProviderMethodTestCase.class), finishedSuccessfully()));
123 | }
124 |
125 | @Test
126 | void discoversFactoryWithDataProviderTestClass() {
127 | var request = request().selectors(selectClass(FactoryWithDataProviderTestCase.class)).build();
128 |
129 | var rootDescriptor = new TestNGTestEngine().discover(request, UniqueId.forEngine("testng"));
130 |
131 | var classDescriptor = getOnlyElement(rootDescriptor.getChildren());
132 | assertThat(classDescriptor.getChildren()).hasSize(4);
133 |
134 | var methodDescriptors = classDescriptor.getChildren().stream() //
135 | .collect(toMap(descriptor -> descriptor.getUniqueId().getLastSegment().getValue(), identity()));
136 | assertThat(methodDescriptors.keySet()).containsExactlyInAnyOrder("a()@0", "a()@1", "b()@0", "b()@1");
137 | }
138 |
139 | @Test
140 | void executesFactoryWithDataProviderTestClass() {
141 | var results = testNGEngine().selectors(selectClass(FactoryWithDataProviderTestCase.class)).execute();
142 |
143 | var capturesFactoryParameters = testNGVersion().compareTo(new ComparableVersion("7.0")) >= 0;
144 | var firstParamSuffix = capturesFactoryParameters ? "(a)" : "";
145 | var secondParamSuffix = capturesFactoryParameters ? "(b)" : "";
146 |
147 | results.containerEvents().assertEventsMatchLooselyInOrder( //
148 | event(engine(), started()), //
149 | event(testClass(FactoryWithDataProviderTestCase.class), started()), //
150 | event(testClass(FactoryWithDataProviderTestCase.class), finishedSuccessfully()), //
151 | event(engine(), finishedSuccessfully()));
152 | results.allEvents().debug().assertEventsMatchLooselyInOrder( //
153 | event(testClass(FactoryWithDataProviderTestCase.class), started()), //
154 | event(test("method:a()@0"), started(), displayName("a[0]" + firstParamSuffix)), //
155 | event(test("method:a()@0"), finishedWithFailure(message("a"))), //
156 | event(testClass(FactoryWithDataProviderTestCase.class), finishedSuccessfully()));
157 | results.allEvents().assertEventsMatchLooselyInOrder( //
158 | event(testClass(FactoryWithDataProviderTestCase.class), started()), //
159 | event(test("method:a()@1"), started(), displayName("a[1]" + secondParamSuffix)), //
160 | event(test("method:a()@1"), finishedWithFailure(message("b"))), //
161 | event(testClass(FactoryWithDataProviderTestCase.class), finishedSuccessfully()));
162 | results.allEvents().assertEventsMatchLooselyInOrder( //
163 | event(testClass(FactoryWithDataProviderTestCase.class), started()), //
164 | event(test("method:b()@0"), started(), displayName("b[0]" + firstParamSuffix)), //
165 | event(test("method:b()@0"), finishedWithFailure(message("a"))), //
166 | event(testClass(FactoryWithDataProviderTestCase.class), finishedSuccessfully()));
167 | results.allEvents().assertEventsMatchLooselyInOrder( //
168 | event(testClass(FactoryWithDataProviderTestCase.class), started()), //
169 | event(test("method:b()@1"), started(), displayName("b[1]" + secondParamSuffix)), //
170 | event(test("method:b()@1"), finishedWithFailure(message("b"))), //
171 | event(testClass(FactoryWithDataProviderTestCase.class), finishedSuccessfully()));
172 | }
173 |
174 | @Test
175 | void executesFactoryMethodTestClass() {
176 | var results = testNGEngine().selectors(selectClass(FactoryMethodTestCase.class)).execute();
177 |
178 | results.allEvents().debug();
179 |
180 | results.containerEvents().assertEventsMatchExactly( //
181 | event(engine(), started()), //
182 | event(testClass(FactoryMethodTestCase.class), started()), //
183 | event(testClass(FactoryMethodTestCase.class), finishedSuccessfully()), //
184 | event(engine(), finishedSuccessfully()));
185 | results.allEvents().assertEventsMatchLooselyInOrder( //
186 | event(testClass(FactoryMethodTestCase.class), started()), //
187 | event(test("method:test()@0"), started()), //
188 | event(test("method:test()@0"), finishedSuccessfully()), //
189 | event(testClass(FactoryMethodTestCase.class), finishedSuccessfully()));
190 | results.allEvents().assertEventsMatchLooselyInOrder( //
191 | event(testClass(FactoryMethodTestCase.class), started()), //
192 | event(test("method:test()@1"), started()), //
193 | event(test("method:test()@1"), finishedSuccessfully()), //
194 | event(testClass(FactoryMethodTestCase.class), finishedSuccessfully()));
195 | }
196 |
197 | @Test
198 | @RequiresTestNGVersion(maxExclusive = "7.6")
199 | void reportsExceptionInDataProviderMethodAsAborted() {
200 | var testClass = DataProviderMethodErrorHandlingTestCase.class;
201 |
202 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
203 |
204 | results.allEvents().assertEventsMatchLooselyInOrder( //
205 | event(testClass(testClass), started()), //
206 | event(container("method:test(int)"), started()), //
207 | event(container("method:test(int)"), abortedWithReason(cause(message("exception in data provider")))), //
208 | event(testClass(testClass), finishedSuccessfully()));
209 | }
210 |
211 | @Test
212 | @RequiresTestNGVersion(min = "7.6")
213 | void reportsExceptionInDataProviderMethodAsFailed() {
214 | var testClass = DataProviderMethodErrorHandlingTestCase.class;
215 |
216 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
217 |
218 | results.allEvents().debug().assertEventsMatchLooselyInOrder( //
219 | event(testClass(testClass), started()), //
220 | event(container("method:test(int)"), started()), //
221 | event(container("method:test(int)"), finishedWithFailure(cause(message("exception in data provider")))), //
222 | event(testClass(testClass), finishedSuccessfully()));
223 | }
224 |
225 | @Test
226 | void reportsNoEventsForDataProviderWithZeroInvocations() {
227 | var testClass = DataProviderMethodEmptyListTestCase.class;
228 |
229 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
230 |
231 | results.allEvents().assertEventsMatchExactly( //
232 | event(engine(), started()), //
233 | event(engine(), finishedSuccessfully()));
234 | }
235 |
236 | @Test
237 | void reportsParallelDataProviderCorrectly() {
238 | var testClass = ParallelDataProviderTestCase.class;
239 |
240 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
241 |
242 | results.containerEvents().debug().assertEventsMatchLooselyInOrder( //
243 | event(testClass(testClass), started()), //
244 | event(container("method:test(java.lang.Integer)"), started()), //
245 | event(container("method:test(java.lang.Integer)"), finishedSuccessfully()), //
246 | event(testClass(testClass), finishedSuccessfully()));
247 | results.testEvents().assertStatistics(
248 | stats -> stats.dynamicallyRegistered(11).started(11).succeeded(11).finished(11));
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/ReportingIntegrationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static org.junit.platform.commons.util.StringUtils.isBlank;
14 | import static org.junit.platform.engine.FilterResult.excluded;
15 | import static org.junit.platform.engine.FilterResult.includedIf;
16 | import static org.junit.platform.engine.discovery.ClassNameFilter.excludeClassNamePatterns;
17 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
18 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
19 | import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId;
20 | import static org.junit.platform.testkit.engine.EventConditions.abortedWithReason;
21 | import static org.junit.platform.testkit.engine.EventConditions.container;
22 | import static org.junit.platform.testkit.engine.EventConditions.displayName;
23 | import static org.junit.platform.testkit.engine.EventConditions.dynamicTestRegistered;
24 | import static org.junit.platform.testkit.engine.EventConditions.engine;
25 | import static org.junit.platform.testkit.engine.EventConditions.event;
26 | import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
27 | import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
28 | import static org.junit.platform.testkit.engine.EventConditions.reportEntry;
29 | import static org.junit.platform.testkit.engine.EventConditions.started;
30 | import static org.junit.platform.testkit.engine.EventConditions.test;
31 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
32 | import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
33 |
34 | import java.util.Map;
35 |
36 | import example.basics.CustomAttributeTestCase;
37 | import example.basics.ExpectedExceptionsTestCase;
38 | import example.basics.InheritingSubClassTestCase;
39 | import example.basics.NestedTestClass;
40 | import example.basics.ParallelExecutionTestCase;
41 | import example.basics.RetriedTestCase;
42 | import example.basics.SimpleTestCase;
43 | import example.basics.SuccessPercentageTestCase;
44 | import example.basics.TimeoutTestCase;
45 | import example.configuration.methods.AbortedBeforeClassConfigurationMethodTestCase;
46 | import example.configuration.methods.FailingBeforeClassConfigurationMethodTestCase;
47 | import example.dataproviders.DataProviderMethodTestCase;
48 |
49 | import org.junit.jupiter.api.Test;
50 | import org.junit.jupiter.params.ParameterizedTest;
51 | import org.junit.jupiter.params.provider.ValueSource;
52 | import org.junit.platform.engine.Filter;
53 | import org.junit.platform.engine.UniqueId;
54 | import org.junit.platform.engine.support.descriptor.MethodSource;
55 | import org.junit.platform.launcher.PostDiscoveryFilter;
56 | import org.testng.SkipException;
57 | import org.testng.internal.thread.ThreadTimeoutException;
58 |
59 | class ReportingIntegrationTests extends AbstractIntegrationTests {
60 |
61 | @ParameterizedTest
62 | @ValueSource(classes = { SimpleTestCase.class, InheritingSubClassTestCase.class })
63 | void executesSuccessfulTests(Class> testClass) {
64 | var results = testNGEngine().selectors(selectMethod(testClass, "successful")).execute();
65 |
66 | results.allEvents().assertEventsMatchExactly( //
67 | event(engine(), started()), //
68 | event(testClass(testClass), started()), //
69 | event(test("method:successful()"), started()), //
70 | event(test("method:successful()"), reportEntry(Map.of("description", "a test that passes"))), //
71 | event(test("method:successful()"), finishedSuccessfully()), //
72 | event(testClass(testClass), finishedSuccessfully()), //
73 | event(engine(), finishedSuccessfully()));
74 | }
75 |
76 | @Test
77 | void executesFailingTests() {
78 | var results = testNGEngine().selectors(selectClass(SimpleTestCase.class)).execute();
79 |
80 | results.allEvents().assertEventsMatchLooselyInOrder( //
81 | event(testClass(SimpleTestCase.class), started()), //
82 | event(test("method:failing()"), started()), //
83 | event(test("method:failing()"), finishedWithFailure(message("boom"))), //
84 | event(testClass(SimpleTestCase.class), finishedSuccessfully()));
85 | }
86 |
87 | @Test
88 | void executesAbortedTests() {
89 | var results = testNGEngine().selectors(selectClass(SimpleTestCase.class)).execute();
90 |
91 | results.allEvents().assertEventsMatchLooselyInOrder( //
92 | event(testClass(SimpleTestCase.class), started()), //
93 | event(test("method:aborted()"), started()), //
94 | event(test("method:aborted()"), abortedWithReason(instanceOf(SkipException.class), message("not today"))), //
95 | event(testClass(SimpleTestCase.class), finishedSuccessfully()));
96 | }
97 |
98 | @Test
99 | void reportsMethodsSkippedDueToFailingDependencyAsAborted() {
100 | var results = testNGEngine().selectors(selectClass(SimpleTestCase.class)).execute();
101 |
102 | results.allEvents().assertEventsMatchLooselyInOrder( //
103 | event(testClass(SimpleTestCase.class), started()), //
104 | event(test("method:skippedDueToFailingDependency()"), started()), //
105 | event(test("method:skippedDueToFailingDependency()"),
106 | abortedWithReason(message(it -> it.contains("depends on not successfully finished methods")))), //
107 | event(testClass(SimpleTestCase.class), finishedSuccessfully()));
108 | }
109 |
110 | @Test
111 | void reportsFailureFromBeforeClassMethod() {
112 | var results = testNGEngine().selectors(
113 | selectClass(FailingBeforeClassConfigurationMethodTestCase.class)).execute();
114 |
115 | results.allEvents().assertEventsMatchLooselyInOrder( //
116 | event(testClass(FailingBeforeClassConfigurationMethodTestCase.class), started()), //
117 | event(testClass(FailingBeforeClassConfigurationMethodTestCase.class),
118 | finishedWithFailure(message("boom"))));
119 | }
120 |
121 | @Test
122 | void reportsAbortedBeforeClassMethod() {
123 | var results = testNGEngine().selectors(
124 | selectClass(AbortedBeforeClassConfigurationMethodTestCase.class)).execute();
125 |
126 | results.allEvents().debug().assertEventsMatchLooselyInOrder( //
127 | event(testClass(AbortedBeforeClassConfigurationMethodTestCase.class), started()), //
128 | event(testClass(AbortedBeforeClassConfigurationMethodTestCase.class),
129 | abortedWithReason(message("not today"))));
130 | }
131 |
132 | @Test
133 | void executesNoTestWhenPostDiscoveryFilterExcludesEverything() {
134 | var testClass = SimpleTestCase.class;
135 |
136 | var results = testNGEngine() //
137 | .selectors(selectClass(testClass)) //
138 | .filters((PostDiscoveryFilter) descriptor -> excluded("not today")) //
139 | .execute();
140 |
141 | results.allEvents().assertEventsMatchExactly( //
142 | event(engine(), started()), //
143 | event(engine(), finishedSuccessfully()));
144 | }
145 |
146 | @Test
147 | void reportsPreviouslyExcludedTestsThatAreExecutedDueToHavingTheSameMethodNameAsDynamicTests() {
148 | PostDiscoveryFilter onlyParameterlessMethods = descriptor -> {
149 | var source = descriptor.getSource().orElse(null);
150 | return includedIf(
151 | !(source instanceof MethodSource) || isBlank(((MethodSource) source).getMethodParameterTypes()));
152 | };
153 |
154 | var results = testNGEngine() //
155 | .selectors(selectClass(DataProviderMethodTestCase.class)) //
156 | .filters(onlyParameterlessMethods) //
157 | .execute();
158 |
159 | results.containerEvents().assertStatistics(stats -> stats //
160 | .dynamicallyRegistered(2) //
161 | .started(1 + 1 + 2) //
162 | .succeeded(1 + 1 + 2) //
163 | .finished(1 + 1 + 2));
164 |
165 | results.testEvents().assertStatistics(stats -> stats //
166 | .dynamicallyRegistered(2 + 2) //
167 | .started(1 + 2 + 2) //
168 | .failed(1 + 2 + 2) //
169 | .succeeded(0) //
170 | .finished(1 + 2 + 2));
171 | }
172 |
173 | @Test
174 | void reportsSuccessPercentageTestCase() {
175 | var testClass = SuccessPercentageTestCase.class;
176 |
177 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
178 |
179 | results.allEvents().assertEventsMatchLooselyInOrder( //
180 | event(testClass(testClass), started()), //
181 | event(container("method:test()"), started()), //
182 | event(dynamicTestRegistered("invoc:0"), displayName("[0]")), //
183 | event(test("invoc:0"), started()), //
184 | event(test("invoc:0"), finishedSuccessfully()), //
185 | event(dynamicTestRegistered("invoc:1"), displayName("[1]")), //
186 | event(test("invoc:1"), started()), //
187 | event(test("invoc:1"), finishedWithFailure(message("boom"))), //
188 | event(dynamicTestRegistered("invoc:2"), displayName("[2]")), //
189 | event(test("invoc:2"), started()), //
190 | event(test("invoc:2"), finishedSuccessfully()), //
191 | event(dynamicTestRegistered("invoc:3"), displayName("[3]")), //
192 | event(test("invoc:3"), started()), //
193 | event(test("invoc:3"), finishedSuccessfully()), //
194 | event(container("method:test()"), finishedSuccessfully()), //
195 | event(testClass(testClass), finishedSuccessfully()));
196 | }
197 |
198 | @Test
199 | void executesAllInvocationsForInvocationUniqueIdSelector() {
200 | var uniqueId = UniqueId.forEngine("testng") //
201 | .append(ClassDescriptor.SEGMENT_TYPE, SuccessPercentageTestCase.class.getName()) //
202 | .append(MethodDescriptor.SEGMENT_TYPE, "test()") //
203 | .append(InvocationDescriptor.SEGMENT_TYPE, "0");
204 |
205 | var results = testNGEngine().selectors(selectUniqueId(uniqueId)).execute();
206 |
207 | results.testEvents().assertStatistics(stats -> stats.finished(4));
208 | }
209 |
210 | @Test
211 | void reportsRetriedTestsCorrectly() {
212 | var testClass = RetriedTestCase.class;
213 |
214 | var results = testNGEngine().selectors(selectMethod(testClass, "test")).execute();
215 |
216 | results.allEvents().assertEventsMatchLooselyInOrder( //
217 | event(testClass(testClass), started()), //
218 | event(container("method:test()"), started()), //
219 | event(dynamicTestRegistered("invoc:0"), displayName("[0]")), //
220 | event(test("invoc:0"), started()), //
221 | event(test("invoc:0"), abortedWithReason(message("retry"))), //
222 | event(dynamicTestRegistered("invoc:1"), displayName("[1]")), //
223 | event(test("invoc:1"), started()), //
224 | event(test("invoc:1"), finishedSuccessfully()), //
225 | event(container("method:test()"), finishedSuccessfully()), //
226 | event(testClass(testClass), finishedSuccessfully()));
227 | }
228 |
229 | @Test
230 | void reportsRetriedTestsWithDataProvidersCorrectly() {
231 | var testClass = RetriedTestCase.class;
232 |
233 | var results = testNGEngine().selectors(selectMethod(testClass, "dataProviderTest")).execute();
234 |
235 | results.allEvents().assertEventsMatchLooselyInOrder( //
236 | event(testClass(testClass), started()), //
237 | event(container("method:dataProviderTest(int)"), started()), //
238 | event(dynamicTestRegistered("invoc:0"), displayName("[0] 1")), //
239 | event(test("invoc:0"), started()), //
240 | event(test("invoc:0"), abortedWithReason(message("retry @ 1"))), //
241 | event(dynamicTestRegistered("invoc:1"), displayName("[1] 1")), //
242 | event(test("invoc:1"), started()), //
243 | event(test("invoc:1"), finishedSuccessfully()), //
244 | event(dynamicTestRegistered("invoc:2"), displayName("[2] 2")), //
245 | event(test("invoc:2"), started()), //
246 | event(test("invoc:2"), finishedSuccessfully()), //
247 | event(container("method:dataProviderTest(int)"), finishedSuccessfully()), //
248 | event(testClass(testClass), finishedSuccessfully()));
249 | }
250 |
251 | @ParameterizedTest
252 | @ValueSource(strings = { "timeOut", "invocationTimeOut" })
253 | void reportsTimedOutTestsAsFailures(String methodName) {
254 | var testClass = TimeoutTestCase.class;
255 |
256 | var results = testNGEngine().selectors(selectMethod(testClass, methodName)).execute();
257 |
258 | results.allEvents().assertEventsMatchLooselyInOrder( //
259 | event(testClass(testClass), started()), //
260 | event(test("method:%s()".formatted(methodName)), started()), //
261 | event(test("method:%s()".formatted(methodName)),
262 | finishedWithFailure(instanceOf(ThreadTimeoutException.class))), //
263 | event(testClass(testClass), finishedSuccessfully()));
264 | }
265 |
266 | @Test
267 | void reportsTestThrowingExpectedExceptionAsSuccessful() {
268 | var testClass = ExpectedExceptionsTestCase.class;
269 |
270 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
271 |
272 | results.allEvents().assertEventsMatchLooselyInOrder( //
273 | event(testClass(testClass), started()), //
274 | event(test("method:test()"), started()), //
275 | event(test("method:test()"), finishedSuccessfully()), //
276 | event(testClass(testClass), finishedSuccessfully()));
277 | }
278 |
279 | @Test
280 | @RequiresTestNGVersion(min = "7.0") // introduced in 7.0
281 | void reportsCustomAttributesAsReportEntries() {
282 | var testClass = CustomAttributeTestCase.class;
283 |
284 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
285 |
286 | results.allEvents().assertEventsMatchLooselyInOrder( //
287 | event(testClass(testClass), started()), //
288 | event(test("method:test()"), started()), //
289 | event(test("method:test()"), reportEntry(Map.of("foo", "bar, baz"))), //
290 | event(test("method:test()"), finishedSuccessfully()), //
291 | event(testClass(testClass), finishedSuccessfully()));
292 | }
293 |
294 | @Test
295 | void reportsParallelInvocations() {
296 | var testClass = ParallelExecutionTestCase.class;
297 |
298 | var results = testNGEngine().selectors(selectClass(testClass)).execute();
299 |
300 | results.containerEvents().assertStatistics(stats -> stats.started(3).finished(3));
301 | results.testEvents().assertStatistics(stats -> stats.started(10).finished(10));
302 |
303 | results.allEvents().debug().assertEventsMatchLooselyInOrder( //
304 | event(testClass(testClass), started()), //
305 | event(container("method:test()"), started()), //
306 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
307 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
308 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
309 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
310 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
311 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
312 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
313 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
314 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
315 | event(test("method:test()"), dynamicTestRegistered("invoc")), //
316 | event(container("method:test()"), finishedSuccessfully()), //
317 | event(testClass(testClass), finishedSuccessfully()));
318 | }
319 |
320 | @Test
321 | void onlyExecutesNestedTestClassesThatMatchClassNameFilter() {
322 | var selectedTestClass = NestedTestClass.class;
323 |
324 | var results = testNGEngine() //
325 | .selectors(selectClass(selectedTestClass)) //
326 | .filters((Filter>) excludeClassNamePatterns(".*A$")) //
327 | .execute();
328 |
329 | results.containerEvents().assertStatistics(stats -> stats.started(2).finished(2));
330 | results.testEvents().assertStatistics(stats -> stats.started(1).finished(1));
331 | }
332 |
333 | }
334 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/RequiresTestNGVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static java.lang.annotation.ElementType.METHOD;
14 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
15 | import static java.util.function.Predicate.isEqual;
16 | import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled;
17 | import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled;
18 | import static org.junit.support.testng.engine.TestContext.testNGVersion;
19 |
20 | import java.lang.annotation.Retention;
21 | import java.lang.annotation.Target;
22 | import java.util.Arrays;
23 |
24 | import org.apache.maven.artifact.versioning.ComparableVersion;
25 | import org.junit.jupiter.api.extension.ConditionEvaluationResult;
26 | import org.junit.jupiter.api.extension.ExecutionCondition;
27 | import org.junit.jupiter.api.extension.ExtendWith;
28 | import org.junit.jupiter.api.extension.ExtensionContext;
29 | import org.junit.platform.commons.support.AnnotationSupport;
30 |
31 | @Retention(RUNTIME)
32 | @Target(METHOD)
33 | @ExtendWith(RequiresTestNGVersion.Extension.class)
34 | @interface RequiresTestNGVersion {
35 |
36 | String min() default "";
37 |
38 | String maxExclusive() default "";
39 |
40 | String[] except() default {};
41 |
42 | class Extension implements ExecutionCondition {
43 | @Override
44 | public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
45 | return AnnotationSupport.findAnnotation(context.getElement(), RequiresTestNGVersion.class).map(
46 | this::satisfiesRequirements).orElse(enabled("no TestNG version requirements"));
47 | }
48 |
49 | private ConditionEvaluationResult satisfiesRequirements(RequiresTestNGVersion requirements) {
50 | var actualVersion = testNGVersion();
51 | if (!requirements.maxExclusive().isBlank()
52 | && actualVersion.compareTo(new ComparableVersion(requirements.maxExclusive())) >= 0) {
53 | return disabled(
54 | "maxExclusive constraint not met: %s > %s".formatted(actualVersion, requirements.maxExclusive()));
55 | }
56 | if (!requirements.min().isBlank()
57 | && actualVersion.compareTo(new ComparableVersion(requirements.min())) < 0) {
58 | return disabled("min constraint not met: %s < %s".formatted(actualVersion, requirements.min()));
59 | }
60 | if (Arrays.stream(requirements.except()).map(ComparableVersion::new).anyMatch(isEqual(actualVersion))) {
61 | return disabled("except constraint not met: %s is contained in %s".formatted(actualVersion,
62 | Arrays.toString(requirements.except())));
63 | }
64 | return enabled("satisfies all TestNG version requirements");
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/TestContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import static org.apache.commons.lang3.StringUtils.removeEnd;
14 |
15 | import org.apache.maven.artifact.versioning.ComparableVersion;
16 |
17 | class TestContext {
18 |
19 | static ComparableVersion testNGVersion() {
20 | return new ComparableVersion(removeEnd(System.getProperty("testng.version", "7.10.2"), "-SNAPSHOT"));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/org/junit/support/testng/engine/TestNGVersionAppendingDisplayNameGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package org.junit.support.testng.engine;
12 |
13 | import java.lang.reflect.Method;
14 | import java.text.MessageFormat;
15 |
16 | import org.junit.jupiter.api.DisplayNameGenerator;
17 |
18 | class TestNGVersionAppendingDisplayNameGenerator extends DisplayNameGenerator.Standard {
19 |
20 | @Override
21 | public String generateDisplayNameForMethod(Class> testClass, Method testMethod) {
22 | var regularDisplayName = super.generateDisplayNameForMethod(testClass, testMethod);
23 | return MessageFormat.format("{0} [{1}]", regularDisplayName, TestContext.testNGVersion());
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/test/resources/junit-platform.properties:
--------------------------------------------------------------------------------
1 | junit.jupiter.displayname.generator.default=org.junit.support.testng.engine.TestNGVersionAppendingDisplayNameGenerator
2 |
--------------------------------------------------------------------------------
/src/test/resources/log4j2-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/AnonymousClassTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class AnonymousClassTestCase {
16 |
17 | @Test
18 | public void test() {
19 | new AnonymousClassTestCase() {
20 | @SuppressWarnings("unused")
21 | @Test
22 | public void method() {
23 | }
24 | };
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/ClassLevelOnlyAnnotationTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | @Test
16 | public class ClassLevelOnlyAnnotationTestCase {
17 |
18 | public void test() {
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/CustomAttributeTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.CustomAttribute;
14 | import org.testng.annotations.Test;
15 |
16 | public class CustomAttributeTestCase {
17 |
18 | @Test(attributes = @CustomAttribute(name = "foo", values = { "bar", "baz" }))
19 | public void test() {
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/DefaultVisibilityBaseTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | abstract class DefaultVisibilityBaseTestCase {
16 |
17 | @Test
18 | void baseMethod() {
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/DefaultVisibilityWithDeclaredMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | class DefaultVisibilityWithDeclaredMethodTestCase extends DefaultVisibilityBaseTestCase {
16 |
17 | @Test
18 | void declaredMethod() {
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/DefaultVisibilityWithoutDeclaredMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | class DefaultVisibilityWithoutDeclaredMethodTestCase extends DefaultVisibilityBaseTestCase {
14 | }
15 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/DryRunTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class DryRunTestCase {
16 |
17 | public static int INVOCATIONS;
18 |
19 | @Test
20 | public void test() {
21 | INVOCATIONS++;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/ExpectedExceptionsTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class ExpectedExceptionsTestCase {
16 |
17 | @Test(expectedExceptions = RuntimeException.class)
18 | public void test() {
19 | throw new RuntimeException("expected");
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/IgnoredTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Ignore;
14 | import org.testng.annotations.Test;
15 |
16 | public class IgnoredTestCase {
17 |
18 | @Test
19 | public void test() {
20 | }
21 |
22 | @Ignore
23 | @Test
24 | public void ignored() {
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/InheritedClassLevelOnlyAnnotationTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | public class InheritedClassLevelOnlyAnnotationTestCase extends ClassLevelOnlyAnnotationTestCase {
14 | }
15 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/InheritingSubClassTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | public class InheritingSubClassTestCase extends SimpleTestCase {
14 | }
15 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/JUnitTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.junit.Test;
14 |
15 | public class JUnitTestCase {
16 |
17 | @Test
18 | public void test() {
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/NestedTestClass.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class NestedTestClass {
16 |
17 | public static class A {
18 | @Test
19 | public void test() {
20 | }
21 | }
22 |
23 | public static class B {
24 | @Test
25 | public void test() {
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/ParallelExecutionTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class ParallelExecutionTestCase {
16 |
17 | @Test(threadPoolSize = 10, invocationCount = 10)
18 | public void test() throws InterruptedException {
19 | Thread.sleep(100);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/RetriedTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import static org.testng.Assert.fail;
14 |
15 | import example.dataproviders.DataProviders;
16 |
17 | import org.testng.IRetryAnalyzer;
18 | import org.testng.ITestResult;
19 | import org.testng.annotations.Test;
20 |
21 | @Test(retryAnalyzer = RetriedTestCase.MyRetryAnalyzer.class)
22 | public class RetriedTestCase {
23 |
24 | int runs;
25 |
26 | public void test() {
27 | if (runs++ == 0) {
28 | fail("retry");
29 | }
30 | }
31 |
32 | @Test(retryAnalyzer = MyRetryAnalyzer.class, dataProvider = "ints", dataProviderClass = DataProviders.class)
33 | public void dataProviderTest(int value) {
34 | if (runs++ == 0) {
35 | fail("retry @ " + value);
36 | }
37 | }
38 |
39 | public static class MyRetryAnalyzer implements IRetryAnalyzer {
40 | @Override
41 | public boolean retry(ITestResult result) {
42 | return true;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/SimpleTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import static org.testng.Assert.fail;
14 |
15 | import org.testng.SkipException;
16 | import org.testng.annotations.Test;
17 |
18 | @Test(groups = "foo")
19 | public class SimpleTestCase {
20 |
21 | @Test(groups = "bar", description = "a test that passes")
22 | public void successful() {
23 | }
24 |
25 | @Test
26 | public void aborted() {
27 | throw new SkipException("not today");
28 | }
29 |
30 | @Test
31 | public void failing() {
32 | fail("boom");
33 | }
34 |
35 | @Test(dependsOnMethods = "failing")
36 | public void skippedDueToFailingDependency() {
37 | }
38 |
39 | @Test(enabled = false)
40 | public void disabled() {
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/SuccessPercentageTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import static org.testng.Assert.fail;
14 |
15 | import org.testng.annotations.Test;
16 |
17 | public class SuccessPercentageTestCase {
18 |
19 | int testRuns;
20 |
21 | @Test(successPercentage = 75, invocationCount = 4)
22 | public void test() {
23 | testRuns++;
24 | if (testRuns < 3) {
25 | fail("boom");
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/TimeoutTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class TimeoutTestCase {
16 |
17 | @Test(timeOut = 1)
18 | public void timeOut() throws Exception {
19 | Thread.sleep(1_000);
20 | }
21 |
22 | @Test(invocationTimeOut = 1)
23 | public void invocationTimeOut() throws Exception {
24 | Thread.sleep(1_000);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/basics/TwoMethodsTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.basics;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class TwoMethodsTestCase {
16 |
17 | @Test
18 | public void one() {
19 | }
20 |
21 | @Test
22 | public void two() {
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/AbortedBeforeClassConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.SkipException;
14 | import org.testng.annotations.BeforeClass;
15 | import org.testng.annotations.Test;
16 |
17 | public class AbortedBeforeClassConfigurationMethodTestCase {
18 |
19 | @BeforeClass
20 | public void beforeClass() {
21 | throw new SkipException("not today");
22 | }
23 |
24 | @Test
25 | public void test() {
26 | // never called
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingAfterClassConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.AfterClass;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingAfterClassConfigurationMethodTestCase {
17 |
18 | @AfterClass
19 | public void afterClass() {
20 | throw new AssertionError("boom");
21 | }
22 |
23 | @Test
24 | public void test() {
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingAfterMethodConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.AfterMethod;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingAfterMethodConfigurationMethodTestCase {
17 |
18 | @AfterMethod
19 | public void afterMethod() {
20 | throw new AssertionError("boom");
21 | }
22 |
23 | @Test
24 | public void test() {
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingAfterSuiteConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.AfterSuite;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingAfterSuiteConfigurationMethodTestCase {
17 |
18 | @AfterSuite
19 | public void afterSuite() {
20 | throw new AssertionError("boom");
21 | }
22 |
23 | @Test
24 | public void test() {
25 | // never called
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingAfterTestConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.AfterTest;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingAfterTestConfigurationMethodTestCase {
17 |
18 | @AfterTest
19 | public void afterTest() {
20 | throw new AssertionError("boom");
21 | }
22 |
23 | @Test
24 | public void test() {
25 | // never called
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingBeforeClassConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.BeforeClass;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingBeforeClassConfigurationMethodTestCase {
17 |
18 | @BeforeClass
19 | public void beforeClass() {
20 | throw new AssertionError("boom");
21 | }
22 |
23 | @Test
24 | public void test() {
25 | // never called
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingBeforeMethodConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.BeforeMethod;
14 | import org.testng.annotations.Test;
15 |
16 | public class FailingBeforeMethodConfigurationMethodTestCase {
17 |
18 | int calls;
19 |
20 | @BeforeMethod
21 | public void beforeMethod() {
22 | calls++;
23 | if (calls > 1) {
24 | throw new AssertionError("boom");
25 | }
26 | }
27 |
28 | @Test
29 | public void a() {
30 | // called
31 | }
32 |
33 | @Test(dependsOnMethods = "a")
34 | public void b() {
35 | // never called
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingBeforeSuiteConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.BeforeMethod;
14 | import org.testng.annotations.BeforeSuite;
15 | import org.testng.annotations.Test;
16 |
17 | public class FailingBeforeSuiteConfigurationMethodTestCase {
18 |
19 | @BeforeSuite
20 | public void beforeSuite() {
21 | throw new AssertionError("boom");
22 | }
23 |
24 | @BeforeMethod
25 | public void beforeMethod() {
26 | // never called
27 | }
28 |
29 | @Test
30 | public void test() {
31 | // never called
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/FailingBeforeTestConfigurationMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import org.testng.annotations.BeforeMethod;
14 | import org.testng.annotations.BeforeTest;
15 | import org.testng.annotations.Test;
16 |
17 | public class FailingBeforeTestConfigurationMethodTestCase {
18 |
19 | @BeforeTest
20 | public void beforeTest() {
21 | throw new AssertionError("boom");
22 | }
23 |
24 | @BeforeMethod
25 | public void beforeMethod() {
26 | // never called
27 | }
28 |
29 | @Test
30 | public void test() {
31 | // never called
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/methods/GroupsConfigurationMethodsTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.methods;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import org.testng.annotations.AfterGroups;
17 | import org.testng.annotations.BeforeGroups;
18 | import org.testng.annotations.Test;
19 |
20 | public class GroupsConfigurationMethodsTestCase {
21 |
22 | public static List EVENTS = new ArrayList<>();
23 |
24 | @BeforeGroups("group1")
25 | public void beforeGroup1() {
26 | EVENTS.add("beforeGroup1");
27 | }
28 |
29 | @AfterGroups("group1")
30 | public void afterGroup1() {
31 | EVENTS.add("afterGroup1");
32 | }
33 |
34 | @BeforeGroups("group2")
35 | public void beforeGroup2() {
36 | EVENTS.add("beforeGroup2");
37 | }
38 |
39 | @AfterGroups("group2")
40 | public void afterGroup2() {
41 | EVENTS.add("afterGroup2");
42 | }
43 |
44 | @Test(groups = "group1")
45 | public void testGroup1() {
46 | EVENTS.add("testGroup1");
47 | }
48 |
49 | @Test(groups = { "group1", "group2" })
50 | public void testGroup1And2() {
51 | EVENTS.add("testGroup1And2");
52 | }
53 |
54 | @Test(groups = "group2")
55 | public void testGroup2() {
56 | EVENTS.add("testGroup2");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/DataProviderThreadCountTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import static java.util.concurrent.TimeUnit.SECONDS;
14 | import static org.testng.Assert.assertTrue;
15 | import static org.testng.xml.XmlSuite.DEFAULT_DATA_PROVIDER_THREAD_COUNT;
16 |
17 | import java.util.Iterator;
18 | import java.util.concurrent.CountDownLatch;
19 | import java.util.stream.IntStream;
20 |
21 | import org.testng.annotations.DataProvider;
22 | import org.testng.annotations.Test;
23 |
24 | public class DataProviderThreadCountTestCase {
25 |
26 | public static final int NUM_INVOCATIONS = DEFAULT_DATA_PROVIDER_THREAD_COUNT + 1;
27 |
28 | final CountDownLatch latch = new CountDownLatch(NUM_INVOCATIONS);
29 |
30 | @DataProvider(name = "numbers", parallel = true)
31 | public static Iterator numbers() {
32 | return IntStream.range(0, NUM_INVOCATIONS) //
33 | .mapToObj(i -> new Object[] { i }) //
34 | .iterator();
35 | }
36 |
37 | @Test(dataProvider = "numbers")
38 | public void test(Integer number) throws Exception {
39 | System.out.println(Thread.currentThread().getName() + ": " + number);
40 | latch.countDown();
41 | assertTrue(latch.await(1, SECONDS));
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/InvocationTrackingListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import org.testng.IClassListener;
14 | import org.testng.ITestClass;
15 |
16 | public class InvocationTrackingListener implements IClassListener {
17 |
18 | public static boolean invoked;
19 |
20 | @Override
21 | public void onBeforeClass(ITestClass testClass) {
22 | invoked = true;
23 | }
24 |
25 | @Override
26 | public void onAfterClass(ITestClass testClass) {
27 | // do nothing
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/ParallelMethodsTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import static java.util.concurrent.TimeUnit.SECONDS;
14 | import static org.testng.Assert.assertTrue;
15 |
16 | import java.util.concurrent.CountDownLatch;
17 |
18 | import org.testng.annotations.Test;
19 |
20 | public class ParallelMethodsTestCase {
21 |
22 | final CountDownLatch latch = new CountDownLatch(2);
23 |
24 | @Test
25 | public void a() throws Exception {
26 | countDownAndAwait();
27 | }
28 |
29 | @Test
30 | public void b() throws Exception {
31 | countDownAndAwait();
32 | }
33 |
34 | private void countDownAndAwait() throws InterruptedException {
35 | latch.countDown();
36 | assertTrue(latch.await(1, SECONDS));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/PreserveOrderTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import static org.testng.Assert.assertTrue;
14 |
15 | import org.testng.ITestContext;
16 | import org.testng.annotations.Test;
17 |
18 | public class PreserveOrderTestCase {
19 |
20 | @Test
21 | public void test(ITestContext context) {
22 | assertTrue(context.getSuite().getXmlSuite().getPreserveOrder());
23 | assertTrue(context.getCurrentXmlTest().getPreserveOrder());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/ReturnValuesTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class ReturnValuesTestCase {
16 |
17 | @Test
18 | public String test() {
19 | return "some bogus return value";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/SystemPropertyProvidingListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import org.testng.IClassListener;
14 | import org.testng.ITestClass;
15 |
16 | public class SystemPropertyProvidingListener implements IClassListener {
17 |
18 | public static final String SYSTEM_PROPERTY_KEY = "test.class";
19 |
20 | @Override
21 | public void onBeforeClass(ITestClass testClass) {
22 | System.setProperty(SYSTEM_PROPERTY_KEY, testClass.getName());
23 | }
24 |
25 | @Override
26 | public void onAfterClass(ITestClass testClass) {
27 | System.clearProperty(SYSTEM_PROPERTY_KEY);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/configuration/parameters/SystemPropertyReadingTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.configuration.parameters;
12 |
13 | import static org.testng.Assert.assertEquals;
14 |
15 | import org.testng.annotations.Test;
16 |
17 | public class SystemPropertyReadingTestCase {
18 |
19 | @Test
20 | public void test() {
21 | assertEquals(System.getProperty(SystemPropertyProvidingListener.SYSTEM_PROPERTY_KEY),
22 | SystemPropertyReadingTestCase.class.getName());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/DataProviderMethodEmptyListTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class DataProviderMethodEmptyListTestCase {
16 |
17 | @Test(dataProvider = "empty", dataProviderClass = DataProviders.class)
18 | public void test(int value) {
19 | // never called
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/DataProviderMethodErrorHandlingTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import org.testng.annotations.Test;
14 |
15 | public class DataProviderMethodErrorHandlingTestCase {
16 |
17 | @Test(dataProvider = "exception", dataProviderClass = DataProviders.class)
18 | public void test(int value) {
19 | // never called
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/DataProviderMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import static org.testng.Assert.fail;
14 |
15 | import org.testng.annotations.Test;
16 |
17 | public class DataProviderMethodTestCase {
18 |
19 | @Test(dataProvider = "strings", dataProviderClass = DataProviders.class)
20 | public void test(String value) {
21 | fail(value);
22 | }
23 |
24 | @Test(dataProvider = "ints", dataProviderClass = DataProviders.class)
25 | public void test(int value) {
26 | fail(String.valueOf(value));
27 | }
28 |
29 | @Test
30 | public void test() {
31 | fail("parameterless");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/DataProviders.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import static java.util.Collections.singletonList;
14 |
15 | import java.util.Iterator;
16 | import java.util.List;
17 | import java.util.stream.Stream;
18 |
19 | import org.testng.annotations.DataProvider;
20 |
21 | public class DataProviders {
22 |
23 | @DataProvider
24 | public static Iterator strings() {
25 | return Stream.of(singletonList("a"), singletonList("b")).map(List::toArray).iterator();
26 | }
27 |
28 | @DataProvider
29 | public static Iterator ints() {
30 | return Stream.of(singletonList(1), singletonList(2)).map(List::toArray).iterator();
31 | }
32 |
33 | @DataProvider
34 | public static Iterator exception() {
35 | throw new RuntimeException("exception in data provider");
36 | }
37 |
38 | @DataProvider
39 | public static Object[][] empty() {
40 | return new Object[0][];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/FactoryMethodTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import static org.testng.Assert.assertNotEquals;
14 |
15 | import org.testng.annotations.Factory;
16 | import org.testng.annotations.Test;
17 |
18 | public class FactoryMethodTestCase {
19 |
20 | private final String a;
21 | private final String b;
22 |
23 | @Factory
24 | public static Object[] factoryData() {
25 | return new Object[] { new FactoryMethodTestCase("a", "b"), new FactoryMethodTestCase("c", "d") };
26 | }
27 |
28 | public FactoryMethodTestCase(String a, String b) {
29 | this.a = a;
30 | this.b = b;
31 | }
32 |
33 | @Test
34 | public void test() {
35 | assertNotEquals(a, b);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/FactoryWithDataProviderTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import static org.testng.Assert.fail;
14 |
15 | import org.testng.annotations.Factory;
16 | import org.testng.annotations.Test;
17 |
18 | public class FactoryWithDataProviderTestCase {
19 |
20 | private final String param;
21 |
22 | @Factory(dataProvider = "strings", dataProviderClass = DataProviders.class)
23 | public FactoryWithDataProviderTestCase(String param) {
24 | this.param = param;
25 | }
26 |
27 | @Test
28 | public void a() {
29 | fail(param);
30 | }
31 |
32 | @Test
33 | public void b() {
34 | fail(param);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/testFixtures/java/example/dataproviders/ParallelDataProviderTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021-2025 the original author or authors.
3 | *
4 | * All rights reserved. This program and the accompanying materials are
5 | * made available under the terms of the Eclipse Public License v2.0 which
6 | * accompanies this distribution and is available at
7 | *
8 | * https://www.eclipse.org/legal/epl-v20.html
9 | */
10 |
11 | package example.dataproviders;
12 |
13 | import java.util.Arrays;
14 | import java.util.Collection;
15 | import java.util.Iterator;
16 | import java.util.stream.IntStream;
17 |
18 | import org.testng.annotations.DataProvider;
19 | import org.testng.annotations.Test;
20 |
21 | public class ParallelDataProviderTestCase {
22 |
23 | @DataProvider(name = "numbers", parallel = true)
24 | public static Iterator numbers() {
25 | return IntStream.of(1, 3, 5, 7, 9, 11, 13, -5, -3, 15, Integer.MAX_VALUE) //
26 | .mapToObj(Arrays::asList) //
27 | .map(Collection::toArray) //
28 | .iterator();
29 | }
30 |
31 | @Test(dataProvider = "numbers")
32 | public void test(Integer number) {
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------