Обновить

Комментарии 5

Cкептически отношусь к использованию @SpringBootTest. В прошлом встречал применения коллегами таких тестов совместно с TestContainers, и у них есть ряд существенных недостатков, кроме собственно того, что описано в статье:
1. Тесты получаются излишне запутанными по структуре.
2. Запуск занимает много времени, что замедляет цикл разработки. Хочется иметь возможность тесты гонять не только в CI/CD.
3. Трудная диагностика сбоев. При падении теста разобраться в причине как правило крайне сложно, зависит конечно от автора, но у меня лично глаз начинает дергаться, если вижу, что упал «SpringBootTest», не видел «понятных» по структуре:
- в логах перемешаны сообщения от TestContainers, тестового фреймворка и бизнес‑логики;
часть компонентов замокано, часть подменено;
- зачастую тестируется не реальная логика, а искусственный контекст приложения, который слабо соотносится с реальным, очень часто видел, как такие тесты вырождались в тестирование каких-то синтетических ситуаций и по сути в тестирование моков. Надо еще держать в уме всю эту магию AutoConfigureJdbc и др (т.е. нужно еще потратить немало когнитивных усилий для того, чтобы понять собственно вводные как этот тест работает, а потом уже только разбираться, а что не работает)

На мой взгляд, более рациональный подход это сочетание: юнит тестов и возможно ограниченных slice-тестов( тестирование репозиториев и контроллеров), возможно в некоторых ситуациях с TestContainers( и то нужно еще 10 раз подумать, если есть компонентные тесты)

Не вижу убедительных аргументов в пользу @SpringBootTest как основного инструмента.

Для компонентного тестирования приложения как «чёрного ящика» на мой взгляд лучше подойти по-другому, у нас например это делается так:

1) Собирается Docker Compose с контейнером с нашим сервисом и контейнерами с сервисами, которые необходим для работы нашего приложения( kafka, wiremock, postgres)

2) Вся эта конфигурация поднимается.

3) Далее есть отдельно код, который собственно взаимодействует с сервисом через kafka, rest-api в зависимости от логики для воспроизведения тесткейсов.

При таком подходе код тестовых сценариев по определению отделен от логики приложения( в @SpringBootTest тоже конечно можно так сделать, но тяжело придерживаться такого стиля), логи теста и приложения отдельно, тестирование близко к реальным сценариям.

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

Можете поподробнее рассказать о вашем процессе тестирования как "черного ящика"? Я правильно понимаю, что это тестирование у вас проходит при сборке на CI? Или это какой-то отдельный этап?

Все тестирование проходит и в ci/cd и локально. Т.е. в ci/cd у нас есть отдельно запуск юнит тестов и отдельно запуск компонентных тестов.

Как выглядят компонентные тесты:

Это отдельный подпроект внутри проекта с сервисом. Там находятся собственно код тестовых сценариев, compose-файлы с помощью которых поднимается окружение необходимо для работы тестируемого сервиса( kafka, postgres и т.д.) и собственно сам сервис.

Режим работы с тестами локально. Поднимаются с помощью gradle таски все контейнеры, необходимы для работы сервиса. Сам сервис можно просто запустить из IDEA или собрать контейнер и также запустить в контейнере с помощью конфигурации в compose файле. Далее запускаются сам код тестов. Если смысл работы сервиса условно заключается в том, что надо вычитать сообщение из топика кафки, обогатить его, послав запрос в другой сервис по ресту и далее положить его в кафку, то тест будет собственно выполнять это: 1) сформируем сообщение в кафку 2) настроим wiremock для эмуляции ответа от внешнего сервиса 3) отправим сообщение в кафку 4) проверим, что в результирующем топике появилось соответствующее сообщение

Режим работы тестов в ci/cd. Все тоже самое с той лишь разницей, что сначала собирается артефакт docker container с сервисом, далее с помощью gradle таски поднимается окружение( kafka, postgres и т.д.),далее поднимается сам контейнер и потом осуществляется запуск компонентных тестов с помощью gradle test из проекта с автотестами.

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

E2E тесты у нас немного вынесены за процесс сборки артефактов сервисов и прогоняются также в том числе локально и в ci cd уже непосредственно перед релизом.

Во многом согласен. Здесь @SpringBootTest используется скорее как "сахар". Сейчас на проекте, который послужил источником для данной статьи мы эту аннотацию не применяем. В основном для целей тестирования работы с БД берем либо @JdbcTest и аналоги, либо тестовую конфигурацию с ручным конфигурированием DataSource (постепенно идем к последнему варианту).

Цель таких тестов для нас - это проверка работы именно с БД. В них нет тестирования всей логики, т.е. мы проверяем, что наши запросы работают именно так, как мы и хотим и именно на такой БД, которая будет на проде.

При локальном тестировании нам много времени экономит Gradle. У нас большое количество модулей небольшого размера, и изменения кода в модуле приводят только к его пересборке. А вот при сборке на CI собирается все с нуля.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации