Skip to content

Commit 2699504

Browse files
committed
Introduce concurrency tests for Spring's JUnit 4 support
Whereas the existing TestContextConcurrencyTests verify support for concurrency in the TestContextManager and TestContext, this commit introduces SpringJUnit4ConcurrencyTests that verify support for concurrent test execution in Spring's JUnit 4 support, namely in the SpringRunner, SpringClassRule, and SpringMethodRule. The tests executed by this new test class come from a hand-picked collection of test classes within the test suite that is intended to cover most categories of tests that are currently supported by the TestContext Framework on JUnit 4. Note, however, that the chosen test classes intentionally do not include any classes that fall under the following categories. - tests that make use of Spring's @DirtiesContext support - tests that make use of JUnit 4's @FixMethodOrder support - tests that commit changes to the state of a shared in-memory database Issue: SPR-5863
1 parent e822e4c commit 2699504

File tree

3 files changed

+182
-11
lines changed

3 files changed

+182
-11
lines changed

spring-test/src/test/java/org/springframework/test/context/TestContextConcurrencyTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
*
4242
* @author Sam Brannen
4343
* @since 5.0
44+
* @see org.springframework.test.context.junit4.concurrency.SpringJUnit4ConcurrencyTests
4445
*/
4546
public class TestContextConcurrencyTests {
4647

spring-test/src/test/java/org/springframework/test/context/junit4/JUnitTestingUtils.java

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,17 +18,25 @@
1818

1919
import java.lang.reflect.Constructor;
2020

21+
import org.junit.experimental.ParallelComputer;
22+
import org.junit.jupiter.api.Assertions;
23+
import org.junit.runner.Computer;
2124
import org.junit.runner.JUnitCore;
2225
import org.junit.runner.RunWith;
2326
import org.junit.runner.Runner;
2427
import org.junit.runner.notification.RunNotifier;
2528

2629
import org.springframework.beans.BeanUtils;
2730

28-
import static org.junit.Assert.*;
31+
import static org.junit.jupiter.api.Assertions.assertAll;
32+
import static org.junit.jupiter.api.Assertions.assertEquals;
2933

3034
/**
31-
* Collection of utilities for testing the execution of JUnit tests.
35+
* Collection of utilities for testing the execution of JUnit 4 based tests.
36+
*
37+
* <p>Note that these utilities use {@link Assertions} from JUnit Jupiter,
38+
* but that should not result in any adverse side effects in terms of
39+
* proper test failure for failed assertions.
3240
*
3341
* @author Sam Brannen
3442
* @since 4.2
@@ -38,8 +46,8 @@ public class JUnitTestingUtils {
3846

3947
/**
4048
* Run the tests in the supplied {@code testClass}, using the {@link Runner}
41-
* it is configured with (i.e., via {@link RunWith @RunWith}) or the default
42-
* JUnit runner, and assert the expectations of the test execution.
49+
* configured via {@link RunWith @RunWith} or the default JUnit runner, and
50+
* assert the expectations of the test execution.
4351
*
4452
* @param testClass the test class to run with JUnit
4553
* @param expectedStartedCount the expected number of tests that started
@@ -65,7 +73,7 @@ public static void runTestsAndAssertCounters(Class<?> testClass, int expectedSta
6573
* (i.e., via {@link RunWith @RunWith}) or the default JUnit runner.
6674
*
6775
* @param runnerClass the explicit runner class to use or {@code null}
68-
* if the implicit runner should be used
76+
* if the default JUnit runner should be used
6977
* @param testClass the test class to run with JUnit
7078
* @param expectedStartedCount the expected number of tests that started
7179
* @param expectedFailedCount the expected number of tests that failed
@@ -93,11 +101,54 @@ public static void runTestsAndAssertCounters(Class<? extends Runner> runnerClass
93101
junit.run(testClass);
94102
}
95103

96-
assertEquals("tests started for [" + testClass + "]:", expectedStartedCount, listener.getTestStartedCount());
97-
assertEquals("tests failed for [" + testClass + "]:", expectedFailedCount, listener.getTestFailureCount());
98-
assertEquals("tests finished for [" + testClass + "]:", expectedFinishedCount, listener.getTestFinishedCount());
99-
assertEquals("tests ignored for [" + testClass + "]:", expectedIgnoredCount, listener.getTestIgnoredCount());
100-
assertEquals("failed assumptions for [" + testClass + "]:", expectedAssumptionFailedCount, listener.getTestAssumptionFailureCount());
104+
// @formatter:off
105+
assertAll(
106+
() -> assertEquals(expectedStartedCount, listener.getTestStartedCount(), "tests started for [" + testClass + "]"),
107+
() -> assertEquals(expectedFailedCount, listener.getTestFailureCount(), "tests failed for [" + testClass + "]"),
108+
() -> assertEquals(expectedFinishedCount, listener.getTestFinishedCount(), "tests finished for [" + testClass + "]"),
109+
() -> assertEquals(expectedIgnoredCount, listener.getTestIgnoredCount(), "tests ignored for [" + testClass + "]"),
110+
() -> assertEquals(expectedAssumptionFailedCount, listener.getTestAssumptionFailureCount(), "failed assumptions for [" + testClass + "]")
111+
);
112+
// @formatter:on
113+
}
114+
115+
/**
116+
* Run all tests in the supplied test classes according to the policies of
117+
* the supplied {@link Computer}, using the {@link Runner} configured via
118+
* {@link RunWith @RunWith} or the default JUnit runner, and assert the
119+
* expectations of the test execution.
120+
*
121+
* <p>To have all tests executed in parallel, supply {@link ParallelComputer#methods()}
122+
* as the {@code Computer}. To have all tests executed serially, supply
123+
* {@link Computer#serial()} as the {@code Computer}.
124+
*
125+
* @param computer the JUnit {@code Computer} to use
126+
* @param expectedStartedCount the expected number of tests that started
127+
* @param expectedFailedCount the expected number of tests that failed
128+
* @param expectedFinishedCount the expected number of tests that finished
129+
* @param expectedIgnoredCount the expected number of tests that were ignored
130+
* @param expectedAssumptionFailedCount the expected number of tests that
131+
* resulted in a failed assumption
132+
* @param testClasses one or more test classes to run
133+
*/
134+
public static void runTestsAndAssertCounters(Computer computer, int expectedStartedCount, int expectedFailedCount,
135+
int expectedFinishedCount, int expectedIgnoredCount, int expectedAssumptionFailedCount,
136+
Class<?>... testClasses) throws Exception {
137+
138+
JUnitCore junit = new JUnitCore();
139+
TrackingRunListener listener = new TrackingRunListener();
140+
junit.addListener(listener);
141+
junit.run(computer, testClasses);
142+
143+
// @formatter:off
144+
assertAll(
145+
() -> assertEquals(expectedStartedCount, listener.getTestStartedCount(), "tests started"),
146+
() -> assertEquals(expectedFailedCount, listener.getTestFailureCount(), "tests failed"),
147+
() -> assertEquals(expectedFinishedCount, listener.getTestFinishedCount(), "tests finished"),
148+
() -> assertEquals(expectedIgnoredCount, listener.getTestIgnoredCount(), "tests ignored"),
149+
() -> assertEquals(expectedAssumptionFailedCount, listener.getTestAssumptionFailureCount(), "failed assumptions")
150+
);
151+
// @formatter:on
101152
}
102153

103154
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2002-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.junit4.concurrency;
18+
19+
import org.junit.Test;
20+
import org.junit.experimental.ParallelComputer;
21+
22+
import org.springframework.test.context.hierarchies.web.DispatcherWacRootWacEarTests;
23+
import org.springframework.test.context.junit4.InheritedConfigSpringJUnit4ClassRunnerAppCtxTests;
24+
import org.springframework.test.context.junit4.MethodLevelTransactionalSpringRunnerTests;
25+
import org.springframework.test.context.junit4.SpringJUnit47ClassRunnerRuleTests;
26+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunnerAppCtxTests;
27+
import org.springframework.test.context.junit4.SpringRunner;
28+
import org.springframework.test.context.junit4.TimedTransactionalSpringRunnerTests;
29+
import org.springframework.test.context.junit4.rules.BasicAnnotationConfigWacSpringRuleTests;
30+
import org.springframework.test.context.junit4.rules.ParameterizedSpringRuleTests;
31+
import org.springframework.test.context.junit4.rules.SpringClassRule;
32+
import org.springframework.test.context.junit4.rules.SpringMethodRule;
33+
import org.springframework.test.context.web.RequestAndSessionScopedBeansWacTests;
34+
import org.springframework.test.context.web.socket.WebSocketServletServerContainerFactoryBeanTests;
35+
import org.springframework.test.web.client.samples.SampleTests;
36+
import org.springframework.test.web.servlet.samples.context.JavaConfigTests;
37+
import org.springframework.test.web.servlet.samples.context.WebAppResourceTests;
38+
import org.springframework.tests.Assume;
39+
import org.springframework.tests.TestGroup;
40+
41+
import static org.springframework.test.context.junit4.JUnitTestingUtils.runTestsAndAssertCounters;
42+
43+
/**
44+
* Concurrency tests for the {@link SpringRunner}, {@link SpringClassRule}, and
45+
* {@link SpringMethodRule} that use JUnit 4's experimental {@link ParallelComputer}
46+
* to execute tests in parallel.
47+
*
48+
* <p>The tests executed by this test class come from a hand-picked collection of test
49+
* classes within the test suite that is intended to cover most categories of tests
50+
* that are currently supported by the TestContext Framework on JUnit 4.
51+
*
52+
* <p>The chosen test classes intentionally do <em>not</em> include any classes that
53+
* fall under the following categories.
54+
*
55+
* <ul>
56+
* <li>tests that make use of Spring's {@code @DirtiesContext} support
57+
* <li>tests that make use of JUnit 4's {@code @FixMethodOrder} support
58+
* <li>tests that commit changes to the state of a shared in-memory database
59+
* </ul>
60+
*
61+
* <p><strong>NOTE</strong>: these tests only run if the {@link TestGroup#LONG_RUNNING
62+
* LONG_RUNNING} test group is enabled.
63+
*
64+
* @author Sam Brannen
65+
* @since 5.0
66+
* @see org.springframework.test.context.TestContextConcurrencyTests
67+
*/
68+
public class SpringJUnit4ConcurrencyTests {
69+
70+
// @formatter:off
71+
private static final Class<?>[] testClasses = new Class[] {
72+
// Basics
73+
/* 9 */ SpringJUnit4ClassRunnerAppCtxTests.class,
74+
/* 9 */ InheritedConfigSpringJUnit4ClassRunnerAppCtxTests.class,
75+
/* 2 */ SpringJUnit47ClassRunnerRuleTests.class,
76+
/* 2 */ ParameterizedSpringRuleTests.class,
77+
// Transactional
78+
/* 2 */ MethodLevelTransactionalSpringRunnerTests.class,
79+
/* 4 */ TimedTransactionalSpringRunnerTests.class,
80+
// Web and Scopes
81+
/* 1 */ DispatcherWacRootWacEarTests.class, /* 2 ignored */
82+
/* 3 */ BasicAnnotationConfigWacSpringRuleTests.class,
83+
/* 2 */ RequestAndSessionScopedBeansWacTests.class,
84+
/* 1 */ WebSocketServletServerContainerFactoryBeanTests.class,
85+
// Spring MVC Test
86+
/* 2 */ JavaConfigTests.class,
87+
/* 3 */ WebAppResourceTests.class,
88+
/* 4 */ SampleTests.class
89+
};
90+
// @formatter:on
91+
92+
/**
93+
* The number of tests in all {@link #testClasses}.
94+
*
95+
* <p>The current number of tests per test class is tracked as a comment
96+
* before each class reference above. The following constant must therefore
97+
* be the sum of those values.
98+
*
99+
* <p>This is admittedly fragile, but there's unfortunately not really a
100+
* better way to count the number of tests without re-implementing JUnit 4's
101+
* discovery algorithm. Plus, the presence of parameterized tests makes it
102+
* even more difficult to count programmatically.
103+
*/
104+
private static final int TESTS = 44;
105+
private static final int FAILED = 0;
106+
private static final int IGNORED = 2;
107+
private static final int ABORTED = 0;
108+
109+
110+
@Test
111+
public void runAllTestsConcurrently() throws Exception {
112+
113+
Assume.group(TestGroup.LONG_RUNNING);
114+
115+
runTestsAndAssertCounters(new ParallelComputer(true, true), TESTS, FAILED, TESTS, IGNORED, ABORTED,
116+
testClasses);
117+
}
118+
119+
}

0 commit comments

Comments
 (0)