Тестируем Spring Boot приложения через Spock Framework |
16.01.2024 00:00 |
Написание тестов — важная часть создания качественного ПО, но в то же время кажется неинтересным и утомительным занятием. Попробуем улучшить этот процесс, объединив сразу несколько крутых технологий. Если говорить про тестирование Java-приложений, то первым на ум приходит JUnit. Этот фреймворк часто используется в Test-Driven Development (TDD) подходе, при котором сначала пишутся тесты на ожидаемое поведение системы, а затем код, который обеспечивает указанное поведение. В качестве альтернативы JUnit выступает Spock Framework, использующий подход Behavior-Driven Development (BDD). Его суть заключается в том, чтобы создавать читаемые, продуктивные и понятные спецификации поведения системы. BDD сценарии, в отличие от TDD, обычно более доступны для понимания и использования всеми участниками команды разработки, включая нетехнических участников команды, таких как бизнес-аналитики. BDD помогает фокусироваться на бизнес-требованиях и легче сопровождать код в долгосрочной перспективе. Учитывая специфику Spock Framework, возникают следующие вопросы:
Чтобы ответить на эти вопросы, далее в статье описан процесс интеграции Spring Boot и Spock Framework, а также приведены примеры тестирования в BDD подходе. ТеорияОсновная структура спецификации (теста)Тестирование в Spock устроено по принципу behavior-driven development (BDD). Это означает, что вместо написания тестов для отдельных компонентов будут разрабатываться спецификации и требования, основанные на работе системы. В Spock используется система блоков given-when-then (и другие), что помогает семантически разделить код:
Так выглядит типичный тест с использованием Spock, написанный на языке Groovy:
Для сравнения, этот же тест на JUnit 5, написанный на Java:
Инструменты SpockОбычно системы состоят из сочетаний множества компонентов, взаимодействие которых со временем становится трудно отслеживать. В этом могут помочь инструменты: Mock, Stub и Spy. Они предоставляют удобный способ имитации и контроля вызовов зависимостей в тестах. Подробнее разобраться в них поможет эта статья. Вкратце:
ПрактикаСовместимость версийSpock Framework последней версии не будет совместим с версиями Spring Boot ниже 2.7. Лучший вариант, чтобы версии Spring и Spock были примерно одного времени выхода. Также будет требоваться версия Groovy, которая соответствует той, что указывается в конце версии Spock. В качестве примера для сборки будет использоваться Gradle. Добавляем следующие зависимости в готовый Spring Boot проект (на момент написания статьи использовалась версия 2.7.12):
Также нужно добавить следующую строку в разделе plugins:
Тесты в Spock пишутся на языке Groovy, что даёт несколько преимуществ. Например, строки в названиях функций (так будет проще описать поведение теста) или поддержка перегрузки операторов, что улучшает читаемость кода. СвойстваВ модуле test для удобства можно создать файл application.proprties, содержащий свойства, который будет использоваться вместо основного во время проведения тестов. Иногда в целях тестирования приходится переопределять уже существующие бины, и чтобы это стало возможно, нужно прописать следующее свойство:
Добавляем H2 базу данных (если надо)Чтобы во время тестов не затрагивать базу данных проекта, можно использовать in-memory database. Для этого добавим ещё одну зависимость:
Также нужно добавить следующие свойства:
Зачастую на проекте используется ORM система, и существует уже готовая схема БД, на основе которой нужно проводить тестирование. Из-за этого могут возникнуть конфликты, которые можно решить, прописав свойства для свойства (да-да, всё верно). Если у вас названия таблиц с маленькой буквы, то добавляем к первому свойству:
Следующее свойство решает проблему инициализации схемы:
Интеграция Spring BootВ качестве примера протестируем сервис для работы с клиентами. Если у тестируемого модуля сложная конфигурация, её можно вынести в отдельный groovy-класс вот таким образом:
Для запуска теста должны быть предоставлены зависимости тестируемых классов. Это можно сделать с помощью DetachedMockFactory выбрав Mock, Stub или Spy. Если для создания класса вы использовали заглушку Mock или Stub, то прописывать вложенные в них зависимости не нужно. Затем полученную конфигурацию легко добавить в контекст к тестируемому объекту (через аннотацию @SpringBootTest или @ContextConfiguration). Классы, добавленные через @Autowired, должны присутствовать в контексте. Соответствующие конфигурации можно создавать для каждого модуля. Таким образом, можно составить такую спецификацию сервиса для работы с клиентами:
Интеграционное тестированиеНичего не мешает также использовать MockMvc, чтобы тестировать работу контроллеров без деплоя на сервер. Вот пример тестирования эндпоинта аутентификации:
Так как это простая конфигурация, то создать Mock, Stub или Spy можно с помощью аннотации @SpringBean. Следующая строка отслеживает, чтобы вызов метода generateToken выполнился только один раз, а также переопределяет его возвращаемое значение:
С помощью этой техники можно изменить внутреннее поведение сервиса для создания различных тест-кейсов. ЗаключениеSpock и Spring Boot при правильной настройке хорошо сочетаются вместе. Как раз на этом этапе часто возникают трудности, особенно у начинающих разработчиков. В статье мне хотелось просто и на примерах описать процесс настройки и тестирования такого сетапа. СсылкиSpock Framework Reference Documentation Spring Module (spockframework.org) |