Тестирование является важным элементом процесса разработки программного обеспечения. При этом работа с тестами может занимать достаточно большое количество времени в сравнении с самой разработкой, в связи с этим возникает необходимость оптимизировать этот процесс. В этой статье рассказывается про плагин Sprinter для IntelliJ IDEA, который может помочь значительно сократить время на локальный запуск тестов.
Проблема
Сколько времени вы обычно тратите в процессе ожидания локального выполнения тестов? Если вы используете Spring Framework и у вас достаточно большой проект, то, скорее всего, инициализация тестов занимает значительное количество времени, что и являлось проблемой в Wrike, с которой я столкнулся. По сути, вам приходится ожидать инициализации каждый раз, когда вы запускаете тесты.
Был добавлен новый тест? Внесено небольшое исправление и необходимо проверить, работает ли оно? Или, может быть, была пропущена функция, в которую нужно было провалиться во время отладки? Чтобы продолжить работу, придется ждать от нескольких секунд до нескольких минут (в зависимости от вашего случая)!
Чтобы хотя бы частично решить эту проблему, я разработал плагин для IntelliJ IDEA.
Суть плагина
Идея заключается в следующем:
Во-первых, не заканчивать работу JVM после каждого запуска теста и сохранять контекст Spring между запусками. Таким образом, время тратится на инициализацию теста только при первом запуске тестов.
Во-вторых, необходимо понять, как будет обновляться код во время работы JVM. С этим может помочь фишка JVM Hotswap, позволяющая редактировать код на лету. Дополнительно можно использовать DCEVM и Hotswap Agent. Более подробно об этом в следующих разделах.
Наконец, обернуть все это в плагин для IntelliJ IDEA ради удобства использования.
Как использовать плагин
Использовать плагин очень просто: находим тест, который хотим запустить, в выпадающем меню с опциями запуска для этого теста появится новая опция: "Run in Launched JVM".
При нажатии на эту опцию проект будет собран, запустится процесс с подключенным дебаггером, и будет выполнен выбранный тест.
И в этот момент можно увидеть разницу с обычным запуском теста: JVM всё ещё работает и ждет следующей команды для выполнения теста. При следующем нажатии той же кнопки (Run in Launched JVM) IDEA выполнит Hotswap измененных файлов и выполнит выбранные тесты.
О чем следует помнить
Этот подход работает благодаря тому, что JVM сохраняет состояние приложения между запусками тестов. Под капотом Spring хранит свой контекст в статической переменной, что упрощает его повторное использование.
Однако это также может быть источником проблем. Например, если вы измените конфигурацию контекста, он автоматически не обновится и не перезагрузится. Или, если в вашем приложении есть какой-то кэш, то его состояние будет сохраняться между прогонами тестов, если вы не будете сбрасывать его явно.
Еще одно ограничение связано с использованием фишки JVM Hotswap для обновления кода. По умолчанию hotswap весьма ограничен — он может обновлять только тела методов, что недостаточно для комфортной разработки.
К счастью, существуют DCEVM и Hotswap Agent! По сути, DCEVM - это патч для HotSpot, который поддерживает гораздо большее количество кейсов для JVM Hotswap. Начиная с Java SE 17, JetBrains Runtime (JBR) включает в себя реализацию DCEVM, и вы можете использовать ее.
Hotswap Agent — это Java-агент, позволяющий выполнять код при первой или повторной загрузке ресурсов или классов. Это значит, что теперь можно обновлять контекст Spring или другую часть состояния приложения при выполнении hotswap.
Hotswap Agent имеет систему плагинов, и довольно много плагинов уже реализовано. Например, есть плагины для Spring, Hibernate и т.д. По моему опыту, они могут работать не со всеми версиями библиотек, но все равно это может быть очень полезно. Кроме того, агент позволяет реализовывать плагины самостоятельно, что позволяет добавить логику при hotswap, специфичную для вашего проекта.
Как использовать DCEVM с плагином
Прежде всего, необходимо установить сам DCEVM и выбрать его в качестве SDK проекта. Затем необходимо зайти в настройки плагина в IntelliJ IDEA (Settings → Tools → Sprinter Settings) и выбрать DCEVM в выпадающем списке "Configured JVM type".
Также вы увидите дополнительные настройки, связанные с DCEVM. Теперь вы можете начать использовать этот плагин с настроенным DCEVM.
Для использования Hotswap Agent совместно с Sprinter необходимо скачать jar агента и указать его местоположение.
Разработчики Hotswap Agent рекомендуют размещать пользовательские плагины рядом с обычным кодом. Однако создание плагинов для Hotswap Agent в отдельных модулях проекта может обеспечить лучшее разделение кода, необходимого только для оптимизации процесса разработки, и всего остального кода.
Используя поле настроек "Modules with custom hotswap agent plugins", вы можете указать список модулей проекта, в которых находятся ваши пользовательские плагины. Плагин Sprinter скомпилирует их вместе с остальными модулями проекта и добавит в classpath, таким образом обеспечив их использование. Не забудьте указать package, в котором находятся ваши плагины, чтобы Hotswap Agent мог их обнаружить.
Плагин создаст файл hotswap-agent.properties
и заполнит его содержимым из поля настроек "Hotswap properties". Документацию по этому файлу можно найти здесь.
Также, хотя это и не является основной целью плагина, сконфигурированный DCEVM можно использовать для запуска обычных приложений, а не только тестов. Для этого необходимо сохранить конфигурацию, которую вы хотите запустить, в IntelliJ IDEA и добавить ее в настройках в поле "Configurations for which DCEVM will be configured".
При следующем запуске все настройки DCEVM будут применены для этой конфигурации.
Для выполнения горячей замены можно воспользоваться обычной функциональностью IntelliJ IDEA (Run → Debugging Actions → Reload Changed Classes). Обратите внимание на существующую проблему: при выполнении этого действия будет производиться попытка компиляции всего проекта, а не только модулей, используемых вашим приложением. Для решения этой проблемы я создал отдельное действие (Build → Compile Modules For Running Configurations), которое делает то же самое, что и оригинальное действие, но компилирует только необходимые модули, тем самым ускоряя hotswap в больших проектах.
Заключение
Подводя итог, плагин Sprinter для IntelliJ IDEA представляет собой перспективное решение для ускорения процесса локального тестирования. Используя фишку JVM Hotswap, мы можем экономить на инициализации тестов.
Однако необходимо помнить об ограничениях и потенциальных проблемах, таких как сохранение состояния приложения и управление Spring-контекста.
Плагин может быть полезен не только в случае использования Spring, но также, например, и Testcontainers и других инструментов, требующих значительного времени на инициализацию.
Поскольку тестирование программного обеспечения продолжает развиваться, инструменты, подобные этому плагину, будут играть важную роль в управлении и оптимизации процесса тестирования.
Для получения дополнительной информации об этом плагине посмотрите репозиторий с исходным кодом или мой доклад о нём на конференции JPoint. Кстати, следующая конференция Joker уже в октябре, и там тоже будет много подобных докладов для Java-разработчиков :)
aleksandy
А ещё можно просто писать настоящие модульные тесты, а тяжелый спринговый контекст поднимать исключительно для интеграционного тестирования, когда модульные тесты прошли.