Как обеспечить нужное состояние базы для каждого теста при работе нескольких разработчиков с разным состоянием базы?
Что проверяют
Понимаете ли вы, что тест не должен зависеть от содержимого чьей-то локальной базы. Ждут ответа, как добиться воспроизводимости: одна и та же схема, данные, которые тест готовит сам, и изоляция между тестами. Следом спрашивают про подводные камни @Transactional в тестах.
Как отвечать
Разложите задачу на три слоя:
- среда: базу поднимает сама сборка. Testcontainers запускает в Docker ту же СУБД и версию, что в проде, с чистого листа. В Spring Boot 3.1 и новее контейнер подключается через
@ServiceConnection, без ручной настройки URL. Один контейнер на весь прогон экономит минуты против запуска на каждый класс; - схема: только миграции Flyway или Liquibase из репозитория. Spring Boot применяет их при старте контекста, так что у всех одинаковая схема, а ручные
ALTERв чьей-то локальной базе в тестах просто не участвуют; - данные: каждый тест готовит то, что нужно ему. Билдеры и фабрики объектов,
@Sqlсо скриптом перед методом, DbUnit или Database Rider для наборов данных. Общий «эталонный» дамп на всех быстро становится хрупким.
Изоляция между тестами. @Transactional на тестовом классе в Spring TestContext по умолчанию откатывает транзакцию после каждого метода. Это работает, пока всё идёт в одном потоке и одной транзакции. Если тест ходит в приложение по реальному HTTP (webEnvironment = RANDOM_PORT), код пишет асинхронно или через REQUIRES_NEW, отката не будет. Тогда чистят явно: TRUNCATE ... RESTART IDENTITY CASCADE перед тестом или уникальные данные в каждом тесте.
Локальная база остаётся для ручной отладки, автотесты от неё не зависят.
Где спотыкаются
Берут H2 вместо реальной СУБД. Режим совместимости поддерживает не весь синтаксис и не все типы, и тест зелёный там, где прод падает.
Пишут тесты, зависящие от порядка запуска: один создаёт пользователя, другой его читает. При параллельном прогоне или запуске одного теста всё ломается.
Верят @Transactional безоговорочно. Кроме потоков, которые откат не видит, есть обратная проблема: без flush() Hibernate не отправляет SQL до коммита, а коммита в тесте нет, и нарушение ограничения базы просто не проявляется.