Spring 5での同時テスト実行

Spring 5での同時テスト実行

1. 前書き

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

この簡単な記事では、use Spring 5 to run our tests in Spring projects concurrentlyを実行する方法を示します。

2. Mavenセットアップ

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


    
        org.apache.maven.plugins
        maven-surefire-plugin
        2.19.1
        
            methods
            true
        
    

並列テスト実行のより詳細な構成については、reference documentationを確認できます。

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

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

Spring 5では、TestContextManagerはローカルスレッド(TestContext)を使用して、各スレッドのTestContextsに対する操作が互いに干渉しないようにします。 したがって、ほとんどのメソッドレベルおよびクラスレベルの同時テストでスレッドセーフが保証されます。

public class TestContextManager {

    // ...
    private final TestContext testContext;

    private final ThreadLocal testContextHolder = new ThreadLocal() {
        protected TestContext initialValue() {
            return copyTestContext(TestContextManager.this.testContext);
        }
    };

    public final TestContext getTestContext() {
        return this.testContextHolder.get();
    }

    // ...
}

同時実行のサポートは、すべての種類のテストに適用されるわけではないことに注意してください。 we need to exclude tests that

  • キャッシュ、データベース、メッセージキューなどの外部共有状態を変更します。

  • 特定の実行順序が必要です。たとえば、JUnit@FixMethodOrderを使用するテスト

  • 一般に@DirtiesContextでマークされているApplicationContextを変更します

5. 概要

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

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