Как устроена автоматизация тестов и интеграционное тестирование
Что проверяют
Различаете ли вы уровни тестов и понимаете ли цену каждого. Java-собеседование почти всегда выходит на Spring и на то, чем именно вы поднимаете зависимости в интеграционных тестах.
Как отвечать
Задайте систему координат пирамидой:
- юнит-тесты: один класс, зависимости подменены через Mockito, миллисекунды на тест. JUnit 5,
@ExtendWith(MockitoExtension.class), проверяем логику, а не фреймворк; - интеграционные: несколько компонентов вместе плюс реальная инфраструктура. Здесь проверяется то, что юнит-тест увидеть не может: SQL-запрос, маппинг сущностей, транзакции, сериализация JSON, конфигурация;
- сквозные (e2e): система целиком через API или интерфейс. Самые ценные и самые хрупкие, поэтому их держат десятками, а не тысячами.
Дальше по Spring: @SpringBootTest поднимает контекст целиком, срезы дешевле и точнее (@DataJpaTest для репозиториев, @WebMvcTest с MockMvc для контроллеров). Базу и брокер поднимайте Testcontainers, то есть настоящий PostgreSQL или Kafka в контейнере на время прогона. Это честнее, чем H2 в памяти: диалект, типы и блокировки у H2 другие, и тест зелёный на нём регулярно падает на проде.
Отдельно скажите про данные и изоляцию: каждый тест готовит своё состояние, транзакция откатывается после теста (@Transactional) либо база чистится между классами. Контекст Spring кешируется между тестами, и его перенастройка через @MockBean этот кеш ломает, отсюда медленный прогон.
Закончите местом тестов в CI: юниты на каждый пул-реквест, интеграционные там же или ночным прогоном, если долгие.
Где спотыкаются
Называют интеграционным любой тест со Spring. Критерий не в аннотации, а в том, проверяется ли стык компонентов.
Мокают репозиторий и считают, что проверили работу с базой. Ошибка в запросе или в ленивой загрузке так не ловится.
Терпят нестабильные тесты. Тест, который падает раз в десять прогонов, обесценивает всю сборку: команда привыкает перезапускать, и настоящее падение проходит незамеченным.