Как стать автором
Обновить

Как сократить время сборки с помощью кеширования контекста от Spring Test

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров2.6K
Всего голосов 5: ↑5 и ↓0+5
Комментарии10

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

Отличная статья. Жду полноценную статью от сообщества, как с этим бороться.

Вот несколько моих комментариев, как я работаю с тестами и моментов, которые я пока что не придумал как обойти:

0. По возможности пишем main классы таким образом, чтобы их можно было бы протестировать с помощью unit или @MockitoUnitTest (это те где @InjectMock, я вечно забываю как оно пишется, поэтому даже кастомную аннотацию завел).

1. Если ваш родительский класс с @SpringBootTest делает before и after, в которых полностью очищает таблицы бд, то можно завести наследника, например ComponentTest (как завещал Борисов), который не будет очищать таблицы (т.е. переопределить before и after родителя), но в котором будет полный контекст спринга. И использовать для компонентных тестов. Т.е. для тех тестов, где мокать было бы слишком много, но чистить бд не надо, либо вы сами в конце теста можете почистить только то, что необходимо.

2. @MockBean на все классы, которые ходят по ресту, в родительском классе. Будет удобно мокать результат, контекст спринга закешен.

3. @MockBean на все @Scheduler. Сами же методы шедулеров однострочные, делегируют работу в другой бин, который и тестируем. Контекст спринга закешен. Больше никаких левых select, когда на дебаге пытаешься найти место, откуда вылетает запрос.

4. Фича флаг, через application.property. В тесте рефлекшеном выставляю нужный параметр, в конце теста возвращаю старый. Контекст кешируется. Но такие тесты не переживут рефакторинг. Может есть лучше способ?

Моя боль:

5. @ConditionOnProperty и несколько имплементации бина, подкидываю имплементацию через аннотацию @TestPropertySource над тестом. Контекст не кешируется. Кто как с этим работает?

6. Не придумал пока что, что делать, когда реально нужен @MockBean. Очень жду советов в вашей статье. Пробовал в родительском классе делать @SpyBean, летели исключения, так времени и не было чтобы разобраться до конца. Пока что просто удаляю @MockBean из кода.

  1. @MockBean на все классы, которые ходят по ресту, в родительском классе.

Я тоже периодически так делаю, но мне постоянно высказывают, что это неправильно и что на самом деле надо мокать сетевые вызовы с помощью Wiremock. А я повторяю, что не вижу ничего страшного в том, чтобы просто замокать сервис. Если сервис неудобно мокать (так бывает, например с фейн клиентами), то сделать под него обёртку и замокать уже её ))

  1. Не придумал пока что, что делать, когда реально нужен @MockBean.

Вот я прямо не знаю. Я выношу все @MockBean в родительский класс (вот как во втором пункте) и как правило мокаю только то, что придётся мокать. То есть то что ходит во внешние сервисы и то, что возвращает настройки. А ситуаций, где нужен полноценный мок для полноценной бизнес-логики... В интеграционных тестах стараюсь избегать. Для этого стараюсь писать юнит тесты (в узком смысле этого выражения) с использованием Мокито

Я тоже периодически так делаю, но мне постоянно высказывают, что это неправильно и что на самом деле надо мокать сетевые вызовы с помощью Wiremock.

Предлагаю компромисс.

Если по ресту ходит готовый клиент -- например, предоставленный сторонним сервисом или feign-клиент, сгенерированный по спеке -- то считаю вполне допустимым его мокать с помощью @MockBean (один раз в базовом тестовом классе, вестимо, чтобы не плодить контексты).

Если же мы используем что-то низкоуровненное -- всякие restTemplate, webClient и прочее, в общем пишем queryParams и pathVariables "руками", то лучше Wiremock. Хотя бы из-за того, что "given" будет написано в другом формате и более наглядно. Иначе получается масло масляное -- вызываем restTemplate с аргументами... и проверяем, что вызываем с правильными аргументами? Нехорошо.

Ещё лучше, конечно, если сторонний эндпоинт выдаст stub-ы в рамках Contract Testing-а (Spring Cloud Contract), но на практике я такого счастья пока не встречал.

Для 3. @MockBean на все @Scheduler. проще отключить скедулинг в тестах.

Логично, что-то не подумал, спасибо, попробую.

может просто не надо spring в тестах?

А как тогда тестировать логику связанную со спрингом? Ну и впринципе как писать интеграционные тесты тогда?

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

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

Вот с БД как? - вот вопрос. Селекты как-то хотелось бы тестировать.

А есть хороший пример таких тестов? Чтобы с тестконтейнерами бд/Кафки, с полной настройкой

воздержусь от слова "хороший", но кейс из этой прекрасной статьи есть в моем примере https://habr.com/ru/articles/824594/. И БД с кафкой тоже

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