Сокращение времени выполнения тестов локально и в CI: Workers, кэширование и область видимости
Практический чек-лист для ускорения работы Jest: сначала измерение, настройка рабочих процессов, уменьшение объема глобальной настройки, повторное использование кэша, параметр isolatedModules и запуск только тестов, которые затронуты проблемой.
Медленный набор тестов постепенно меняет способ работы команды: люди запускают тесты реже, отправляют код в CI для проверки и ждут самое долгое время именно тогда, когда это меньше всего возможно — во время выпуска временного исправления. Эти затраты увеличиваются, когда помощники для написания кода на основе ИИ быстро генерируют изменения, а набор тестов остается основной защитой. Jest поставляется с множеством опций настройки и разумными значениями по умолчанию, поэтому работа «из коробки» обычно подходит, но несколько корректировок могут значительно сократить время выполнения как на ноутбуке, так и в CI. Ни одна из этих настроек не является сложной; вместе они составляют полезный чек-лист.
Измеряйте перед настройкой
Каждое из перечисленных ниже изменений имеет свою цену или компромисс, поэтому начните с чисел. Замерьте время полного запуска при отключенной кэш-памяти (jest --no-cache) чтобы получить исходные показатели, затем внесите по одному изменению и снова измерьте время.
Настройте параллелизм в соответствии с мощностями машины
По умолчанию Jest запускает файлы тестов в параллельных рабочих процессах, что обычно хорошо, но не всегда является оптимальным решением. Это можно настроить с помощью двух флагов:
--runInBandзапускает все тесты последовательно в текущем процессе без использования рабочих процессов. Это может быть быстрее для проектов серверной части, в которых тесты используют дорогостоящий ресурс, или на средствах CI с очень малым количеством ядер, где создание рабочих процессов стоит дороже, чем приносит пользы.--maxWorkersопределяет количество рабочих процессов, которые запускает Jest. Он принимает число или процент доступных ядер;50%— разумная начальная величина, оставляющая место для работы остальных компонентов системы.
Подходящее значение зависит от аппаратного обеспечения, поэтому его необходимо измерять как локально, так и на средствах CI отдельно. Серверы CI часто указывают большее количество ядер, чем они на самом деле могут использовать при нагрузке, и чрезмерное их использование замедляет тесты, а не ускоряет их.
Сохраняйте простоту глобальной настройки
Файл глобальной настройки удобен в крупных кодовых базах: моки, полифилы и утилиты тестирования регистрируются один раз, и каждый тест получает к ним доступ. Однако все файлы тестов оплачивают использование этих ресурсов, включая те, которым они не нужны. Объемные импорты, настройки базы данных или большие реестры моков в setupFilesAfterEnv могут превратить иначе мгновенно выполняющиеся тесты в медленные.
Перемещайте ресурсоемкие настройки поближе к тестам, которые их нуждаются: явно импортируйте вспомогательные функции, используйте метод beforeAll в соответствующем файле или создайте отдельный проект Jest с собственной настройкой для интеграционных тестов.
Повторное использование кэша
Вторые запуски обычно происходят быстрее, чем первые, поскольку Jest кэширует преобразованные файлы и другие метаданные. Это особенно заметно в режиме наблюдения, но CI также получает преимущества, если кэш сохраняется между задачами. Укажите cacheDirectory на стабильный путь и сохраняйте его с помощью функции кэширования вашей системы CI, используя в качестве ключа файл блокировки и конфигурацию Jest, чтобы каждый пайплайн не запускался заново.
Использование режима наблюдения локально
Для локальной работы jest --watch — это лучший механизм обратной связи, предоставляемый Jest. Он перезапускает только те тесты, которые связаны с изменёнными файлами, а интерактивный интерфейс позволяет фильтровать их по имени файла или шаблону имени теста. Он не предназначен для CI: пайплайну нужен один запуск, который завершается кодом состояния, поэтому режим наблюдения следует использовать на машинах разработчиков.
Включение модулей isolatedModules для TypeScript
Когда тесты на TypeScript выполняются с использованием ts-jest, полная проверка типов каждого файла создает значительную нагрузку. Включение опции isolatedModules заставляет трансформатор компилировать каждый файл отдельно, без использования информации о типах из остальной части программы. Команды, работающие над проектами на Angular, отмечают заметное ускорение работы благодаря этой опции, причем безопасность кода практически не снижается, если использоваться параметр tsc --noEmit или если редактор продолжает проверять код на типы. Местоположение этой опции зависит от версии ts-jest, поэтому необходимо ознакомиться с актуальной документацией.
Тестируйте только то, что меняется при изменениях
Нет причин запускать весь набор тестов из-за изменения, касающегося лишь одного пакета. Сам Jest позволяет сузить диапазон тестирования с помощью параметров --onlyChanged или --changedSince=<branch>, которые используют систему контроля версий для поиска связанных тестов. В монорепозитории системы сборки, такие как Nx, идут ещё дальше, анализируя структуру проекта и запуская тесты только для тех проектов, которые затронуты текущим изменением.
Сохраняйте хотя бы один полный запуск тестов, например на основной ветке или еженощно, чтобы обнаружить всё, что может ускользнуть при анализе зависимостей.
Рассмотрите Vitest
Vitest в значительной степени совместим с API Jest, находится под активным обслуживанием и работает с распространёнными фреймворками JavaScript, включая Nuxt. Для проектов, уже построенных на Vite, он часто является более естественным выбором, и многие команды сначала обращаются к нему при создании новых проектов. Большинство вышеупомянутых рекомендаций — измерение производительности, ограничения рабочих процессов, минималистичная настройка и запуск только тестов, которые влияют на результат — также применимы к Vitest. Если вы рассматриваете возможность полного отказа от стороннего инструмента для запуска тестов, ознакомьтесь с заменой Jest на встроенный инструмент для запуска тестов Node.
Когда настройки уже не помогают
В конечном итоге никакие изменения в настройках не смогут превзойти скорость более мощного оборудования. Новый ноутбук или более мощный самостоятельно размещённый инструмент для автоматизированных тестов может стать самым дешёвым способом улучшения производительности, когда сам набор тестов уже находится в хорошем состоянии.
Основные выводы
- Установите базовый уровень без кэширования и меняйте по одному параметру за раз.
- Установите значения
--maxWorkersили--runInBandв соответствии с реальной производительностью каждой среды. - Перенесите ресурсоемкие процедуры настройки из глобальных хуков в тесты, которые ими нуждаются.
- Сохраняйте кэш Jest между запусками CI; режим наблюдения используйте только локально.
- Пусть параметр
isolatedModulesпропускает проверку типов для отдельных файлов, в то время как отдельный шагtscобеспечивает точность типов. - На фичных ветках запускайте только соответствующие тесты, а на основной ветке — полный набор тестов.