Ответ
Юнит-тесты с БД — это, строго говоря, интеграционные тесты. Для их изоляции и воспроизводимости используют следующие подходы:
1. In-memory база данных (H2, HSQLDB)
- Быстрая настройка, не требует внешних зависимостей.
- Может отличаться диалектом SQL от продакшн-БД.
@Test public void testWithH2() { DataSource ds = new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); // Использование ds в репозитории... }
2. Testcontainers (рекомендуемый для интеграционных тестов)
- Запускает реальную БД (PostgreSQL, MySQL) в Docker-контейнере.
-
Гарантирует полную совместимость, но работает медленнее.
@Testcontainers class RepositoryTest { @Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15"); @Test void test() { String jdbcUrl = postgres.getJdbcUrl(); // Подключение и тестирование... } }
3. Транзакции с откатом (Rollback)
- Используется в Spring-приложениях для очистки состояния после каждого теста.
@SpringBootTest @Transactional @Rollback class ServiceTest { @Test void testInTransaction() { // Изменения в БД будут откачены после теста } }
Ключевые принципы:
- Изоляция: Каждый тест должен начинаться с чистого состояния.
- Скорость: Такие тесты выполняются медленнее, их следует отделять от чистых юнит-тестов (например, аннотацией
@IntegrationTest). - Идемпотентность: Результат теста не должен зависеть от порядка выполнения.