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 ThreadLocal testContextHolder = 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 .