1. введение
Начиная с JUnit 4 , тесты могут выполняться параллельно, чтобы увеличить скорость для больших наборов. Проблема заключалась в том, что параллельное выполнение тестов не полностью поддерживалось платформой Spring TestContext до Spring 5 .
В этой краткой статье мы покажем, как использовать Spring 5 для одновременного выполнения наших тестов в Spring проектах .
2. Настройка Maven
Напомним, что для параллельного запуска тестов JUnit нам необходимо настроить плагин maven-surefire-plugin , чтобы включить эту функцию:
org.apache.maven.plugins maven-surefire-plugin 2.19.1 methods true
Вы можете ознакомиться с справочной документацией для получения более подробной конфигурации параллельного выполнения тестов.
3. Параллельный тест
Следующий пример теста завершится неудачей при параллельном запуске для версий до Spring 5 .
Тем не менее, он будет работать гладко в Весна 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 ThreadLocaltestContextHolder = new ThreadLocal () { protected TestContext initialValue() { return copyTestContext(TestContextManager.this.testContext); } }; public final TestContext getTestContext() { return this.testContextHolder.get(); } // ... }
Обратите внимание, что поддержка параллелизма не применяется ко всем видам тестов; нам нужно исключить тесты, которые :
- изменение внешних общих состояний, таких как состояния в кэшах, базах данных, очередях сообщений и т. Д.
- требуются конкретные заказы на выполнение, например, тесты, использующие JUnit ‘s @fixmethod order
- измените ApplicationContext , которые обычно помечены @DirtiesContext
5. Резюме
В этом кратком руководстве мы показали базовый пример использования Spring 5 для параллельного выполнения тестов.
Как всегда, пример кода можно найти на Github .