Интеграционное тестирование REST API с Cucumber, Spring Restdocs и Spring Cloud Contract

Модульные и интеграционные тесты серьёзно упрощают жизнь простого разработчика, позволяя выявить большую часть ошибок и проблем ещё на ранних стадиях разработки. Отдельного упоминания заслуживают фреймворки Spring Restdocs и Spring Cloud Contract, использование которых в интеграционных тестах позволяет сгенерировать сниппеты, заглушки и контракты тестируемых REST API.

Cucumber, Spring Restdocs и Spring Cloud Contract

Использование Spring Restdocs позволяет в ходе выполнения интеграционных тестов сгенерировать сниппеты и документацию для REST API, а совместно со Spring Cloud Contract ещё и заглушки и контракты, которые могут в дальнейшем использоваться при разработке клиентов.

Cucumber упрощает написание тестов при разработке на основе поведения или BDD (Behaviour Driven Development). При его использовании сценарии поведения тестируемого компонента можно описывать при помощи обычного языка с применением языка Gherkin, который регламентирует структуру сценария. Например:

Более подробно о Cucumber и Gherkin можно узнать из официальной документации. Также в мои планы входит написание подробной статьи на тему тестирования кода с Cucumber. Однако в рамках данной статьи я буду описывать процесс интеграции Cucumber и Spring Restdocs/Spring Cloud Contract.

Тестовый проект

Тестовым проектом будет простой REST-сервис с авторизацией и с хранением данных в БД. Зависимости проекта:

Подготовка к написанию тестов

При разработке на основе поведения с использованием Cucumber, процесс разработки начинается с описания функциональности и сценариев её использования. В качестве примера используем указанное уже выше описание:

Теперь нам понадобится класс, который будет выполнять тесты на основе описанного сценария.

Аннотацией @RunWith мы указываем, что тест должен выполняться с Cucucmber.

Аннотацией @CucumberOptions мы настраиваем Cucumber:

  • Свойство strict=true делает реализацию всех шагов обязательным
  • Свойство glue указывает пакет в котором Cucumber будет рекурсивно искать реализации шагов
  • Свойство features указывает путь, где находятся описания функциональностей. В качестве значения можно указать как директорию, так и конкретный файл как это сделано в нашем случае.

Если мы сейчас попробуем выполнить тест, то в ответ получим что-то вроде:

Как следует из лога, чтобы тесты выполнились, нам нужно реализовать указанные шаги. Но перед реализацией шагов нужно интегрировать поддержку Spring и его компонентов.

Интеграция Spring и Cucumber

Основная сложность в интеграции Spring и его компонентов в том, что Cucumber не поддерживает многие возможности JUnit вроде @Before, @After и @Rule, а также не даёт запустить тесты с @RunWith(SpringRunner.class), следовательно аннотации вроде @AutoConfigureRestDocs и @AutoConfigureMockMvc будут работать некорректно, либо не будут работать вообще.

Первое, что нужно сделать — создать класс, который будет инициализировать контекст Spring и который будут наследовать классы, содержащие реализацию шагов:

Аннотация @MockBean позволяет замокать компоненты контекста приложения Spring.

Реализация тестов

Теперь можно реализовать тестовые сниппеты. Для этого создадим новый класс:

Результат выполнения тестов будет:

Вы можете заметить, что сам тестовый код ничем не отличается от того, что вы пишете в обычных интеграционных тестах Spring.

При стандартном подходе к тестированию весь тестовый код выглядел бы следующим образом:

Ссылки