1. 序章

JUnit 4 以降、テストを並行して実行して、より大きなスイートの速度を上げることができます。 問題は、 Spring5より前のSpringTestContextFrameworkでは同時テスト実行が完全にサポートされていなかったことです。

この簡単な記事では、Spring5を使用してSpringプロジェクトでテストを同時に実行する方法を示します。

2. Mavenのセットアップ

注意として、 JUnit テストを並行して実行するには、maven-surefire-pluginを構成して次の機能を有効にする必要があります。

<build>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
        <configuration>
            <parallel>methods</parallel>
            <useUnlimitedThreads>true</useUnlimitedThreads>
        </configuration>
    </plugin>
</build>

並列テスト実行の詳細な構成については、リファレンスドキュメントを確認してください。

3. 同時テスト

次のテスト例は、 Spring5より前のバージョンで並行して実行すると失敗します。

ただし、 Spring5ではスムーズに実行されます。

@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. フードの下

以前のバージョンのフレームワークがテストの同時実行をサポートしていなかった主な理由は、TestContextManagerによるTestContextの管理によるものでした。

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. 概要

このクイックチュートリアルでは、 Spring5を使用してテストを並行して実行する基本的な例を示しました。

いつものように、サンプルコードはGithubにあります。