Spring 5中的並發測試執行
1.簡介
從JUnit 4開始,可以並行運行測試以提高大型套件的速度。問題是Spring 5之前的Spring TestContext Framework不能完全支持並發測試執行。
在這篇快速文章中,我們將展示如何使用Spring 5在Spring項目中同時運行我們的測試。
2. Maven安裝
提醒一下,要並行運行JUnit測試,我們需要配置maven-surefire-plugin以啟用該功能:
<build>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-surefire-plugin</artifactId>
 <version>2.19.1</version>
 <configuration>
 <parallel>methods</parallel>
 <useUnlimitedThreads>true</useUnlimitedThreads>
 </configuration>
 </plugin>
 </build>
您可以查看參考文檔以獲取有關並行測試執行的更詳細的配置。
3.並發測試
對於Spring 5之前的版本並行運行時,以下示例測試將失敗。
但是,它將在Spring 5順利運行:
@RunWith(SpringRunner.class)
 @ContextConfiguration(classes = Spring5JUnit4ConcurrentTest.SimpleConfiguration.class)
 public class Spring5JUnit4ConcurrentTest implements ApplicationContextAware, InitializingBean {
 @Configuration
 public static class SimpleConfiguration {}
 private ApplicationContext applicationContext;
 private boolean beanInitialized = false;
 @Override
 public void afterPropertiesSet() throws Exception {
 this.beanInitialized = true;
 }
 @Override
 public void setApplicationContext(
 final ApplicationContext applicationContext) throws BeansException {
 this.applicationContext = applicationContext;
 }
 @Test
 public void whenTestStarted_thenContextSet() throws Exception {
 TimeUnit.SECONDS.sleep(2);
 assertNotNull(
 "The application context should have been set due to ApplicationContextAware semantics.",
 this.applicationContext);
 }
 @Test
 public void whenTestStarted_thenBeanInitialized() throws Exception {
 TimeUnit.SECONDS.sleep(2);
 assertTrue(
 "This test bean should have been initialized due to InitializingBean semantics.",
 this.beanInitialized);
 }
 }
當按順序運行時,以上測試大約需要6秒鐘才能通過。使用並發執行,只需要大約4.5秒–這對於我們期望在大型套件中節省多少時間來說是非常典型的。
4.內幕
先前版本的框架不支持同時運行測試的主要原因是由於TestContext對TestContextManager的管理。
在Spring 5 , TestContextManager使用局部線程– TestContext –確保每個線程中對TestContexts操作不會相互干擾。因此,對於大多數方法級別和類級別的並發測試,可以保證線程安全性:
public class TestContextManager {
 // ...
 private final TestContext testContext;
 private final ThreadLocal<TestContext> testContextHolder = new ThreadLocal<TestContext>() {
 protected TestContext initialValue() {
 return copyTestContext(TestContextManager.this.testContext);
 }
 };
 public final TestContext getTestContext() {
 return this.testContextHolder.get();
 }
 // ...
 }
請注意,並發支持不適用於所有測試。我們需要排除以下測試:
- 更改外部共享狀態,例如緩存,數據庫,消息隊列等中的狀態。
 -   需要特定的執行順序,例如,使用
JUnit的@FixMethodOrder -   修改
ApplicationContext,通常用@DirtiesContext標記 
5.總結
在本快速教程中,我們展示了一個使用Spring 5並行運行測試的基本示例。
與往常一樣,示例代碼可以在Github上找到。