Как ускорить выполнение большого пакета юнит-тестов
Что проверяют
Умеете ли вы найти, на что реально уходит время, прежде чем крутить настройки. Следом спрашивают, как включить параллельный запуск в JUnit 5 и что сломается, если тесты не изолированы друг от друга.
Как отвечать
Сначала замер: отчёты Surefire с временем по классам, Gradle --scan или сортировка XML-отчётов по длительности. Почти всегда выясняется, что основное время съедают «юнит-тесты», которые на деле поднимают Spring-контекст. Дальше рычаги:
- настоящие юнит-тесты: класс создаётся через конструктор, зависимости подменяются Mockito, без
@SpringBootTest. Такой тест идёт миллисекунды, а не секунды; - срезы и кэш контекста: где контекст нужен, берут
@WebMvcTestили@DataJpaTest. Spring кэширует контекст между классами с одинаковой конфигурацией, а@DirtiesContextи разный набор@MockitoBean(раньше@MockBean) этот кэш ломают; - параллелизм в JUnit 5: по умолчанию выключен. Включается в
junit-platform.propertiesпараметрамиjunit.jupiter.execution.parallel.enabled=trueиjunit.jupiter.execution.parallel.mode.default=concurrent. Общие ресурсы защищают@ResourceLock, неготовые классы помечают@Execution(ExecutionMode.SAME_THREAD); - форки JVM: в Surefire
forkCount=1C(по форку на ядро) сreuseForks=true, в GradlemaxParallelForks. Отдельный форк на каждый класс дорог из-за старта JVM; - сборка: Gradle пропускает тесты неизменившихся модулей, а build cache переносит это между машинами. В Maven собирают только затронутые модули через
-plвместе с-amd; - ожидания:
Thread.sleepв тестах заменяют на Awaitility, а время подменяют черезClock.
Где спотыкаются
Включают параллельный режим на наборе со статическим состоянием и общими файлами. Время падает, зато появляются нестабильные тесты, которые потом чинят неделями.
Предлагают JMH для поиска медленных тестов. JMH это инструмент для микробенчмарков кода, а не профайлер тестового набора.
Главным способом называют удаление тестов. Дубли убирать можно, но ускорение за счёт покрытия интервьюер засчитает как минус.