Параллельное выполнение теста весной 5

Параллельное выполнение теста весной 5

1. Вступление

Начиная сJUnit 4, тесты можно запускать параллельно, чтобы увеличить скорость для более крупных пакетов. Проблема заключалась в том, что параллельное выполнение теста не полностью поддерживалосьSpring TestContext Framework доSpring 5.

В этой быстрой статье мы покажем, какuse Spring 5 to run our tests in Spring projects concurrently.

2. Maven Setup

Напоминаем, что для параллельного запуска тестов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. Под капотом

Основная причина, по которой предыдущие версии платформы не поддерживали одновременное выполнение тестов, была связана с управлениемTestContextTestContextManager.

ВSpring 5TestContextManager использует локальный поток -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 ’s@FixMethodOrder

  • изменитьApplicationContext, которые обычно обозначаются@DirtiesContext

5. Резюме

В этом кратком руководстве мы показали базовый пример использованияSpring 5 для параллельного запуска тестов.

Как всегда, пример кода можно найтиover on Github.