Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Что такое библиотека Testcontainers
Testcontainers это open-source Java библиотека, которая позволяет легко использовать Docker контейнеры для интеграционного тестирования. Она обеспечивает чистую и надёжную среду тестирования.
Основное назначение
Testcontainers автоматически запускает Docker контейнеры с базами данных, очередями сообщений и другими сервисами для тестов:
- PostgreSQL, MySQL, MongoDB
- Redis, RabbitMQ, Kafka
- Elasticsearch, MinIO
- Любые Docker образы
Проблемы без Testcontainers
// ПЛОХО - тесты зависят от локального окружения
@Test
public void testSaveUser() {
// Нужно чтобы PostgreSQL был запущен локально
// Нужно чтобы БД была инициализирована
// Разные разработчики - разные настройки
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/test_db");
// ...
}
Проблемы:
- Зависимость от локального окружения
- CI/CD сложнее настраивать
- Тесты не воспроизводятся на разных машинах
- Конфликты портов
- Грязное состояние БД между тестами
Решение с Testcontainers
// ХОРОШО - каждый тест получает чистый контейнер
@Testcontainers
@DataJpaTest
public class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("test_db")
.withUsername("test")
.withPassword("test");
@Autowired
private UserRepository userRepository;
@Test
public void testSaveAndFindUser() {
User user = new User("john@example.com", "John");
userRepository.save(user);
User found = userRepository.findByEmail("john@example.com");
assertThat(found.getName()).isEqualTo("John");
}
}
Преимущества:
- Автоматически запускается контейнер перед тестами
- Автоматически удаляется после тестов
- Каждый тест в чистой среде
- Работает везде - локально, в CI/CD
- Воспроизводимо на любой машине
Установка
Зависимости в pom.xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.3</version>
<scope>test</scope>
</dependency>
<!-- PostgreSQL контейнер -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.3</version>
<scope>test</scope>
</dependency>
<!-- JUnit 5 интеграция -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.3</version>
<scope>test</scope>
</dependency>
Примеры использования
1. PostgreSQL тесты
@Testcontainers
public class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("testuser")
.withPassword("testpass");
@BeforeAll
static void setUp() {
System.setProperty("spring.datasource.url", postgres.getJdbcUrl());
System.setProperty("spring.datasource.username", postgres.getUsername());
System.setProperty("spring.datasource.password", postgres.getPassword());
}
@Test
void testCreateUser() {
User user = new User("test@example.com", "Test User");
userRepository.save(user);
assertTrue(userRepository.existsByEmail("test@example.com"));
}
}
2. Redis тесты
@Testcontainers
public class CacheServiceTest {
@Container
static GenericContainer<?> redis =
new GenericContainer<>("redis:7")
.withExposedPorts(6379);
private CacheService cacheService;
@BeforeEach
void setUp() {
String host = redis.getHost();
Integer port = redis.getFirstMappedPort();
cacheService = new CacheService(host, port);
}
@Test
void testCacheStorage() {
cacheService.set("key1", "value1");
assertEquals("value1", cacheService.get("key1"));
}
}
3. MySQL + RabbitMQ
@Testcontainers
public class IntegrationTest {
@Container
static MySQLContainer<?> mysql =
new MySQLContainer<>("mysql:8")
.withDatabaseName("testdb")
.withUsername("root")
.withPassword("password");
@Container
static RabbitMQContainer rabbit =
new RabbitMQContainer("rabbitmq:3-management");
@Test
void testIntegration() {
// Тест с обоими контейнерами
}
}
4. Пользовательский контейнер
@Testcontainers
public class CustomContainerTest {
@Container
static GenericContainer<?> customApp =
new GenericContainer<>("myapp:latest")
.withExposedPorts(8080)
.withEnv("APP_MODE", "test")
.withCommand("/bin/sh", "-c", "sleep 10")
.waitingFor(Wait.forHttp("/health")
.forStatusCode(200));
@Test
void testCustomApp() {
String url = "http://" + customApp.getHost() + ":"
+ customApp.getFirstMappedPort();
// Используем контейнер
}
}
Advanced Features
1. Инициализация данных
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withInitScript("init.sql") // SQL скрипт для инициализации
.withCopyFileToContainer(
MountableFile.forClasspathResource("schema.sql"),
"/docker-entrypoint-initdb.d/");
2. Сетевые контейнеры
@Testcontainers
public class NetworkTest {
@Container
static Network network = Network.newNetwork();
@Container
static MySQLContainer<?> mysql =
new MySQLContainer<>("mysql:8")
.withNetwork(network)
.withNetworkAliases("mysql");
@Container
static GenericContainer<?> app =
new GenericContainer<>("myapp:latest")
.withNetwork(network)
.withEnv("DB_HOST", "mysql");
}
3. Docker Compose
@Testcontainers
public class DockerComposeTest {
@Container
static DockerComposeContainer compose =
new DockerComposeContainer(new File("docker-compose.yml"))
.withExposedService("postgres", 5432);
@Test
void test() {
// Используем сервисы из docker-compose
}
}
Лучшие практики
✅ Используй @Testcontainers и @Container для удобства ✅ Кэшируй контейнеры между тестами где возможно ✅ Используй health checks для проверки готовности ✅ Логируй контейнеры при отладке ✅ Удаляй временные файлы после тестов
❌ Не используй реальные БД в тестах ❌ Не запускай слишком много контейнеров ❌ Не забывай про timeout при медленных операциях
Производительность
Первый запуск может быть медленным (скачивание образов), но:
- Docker кэширует образы
- Последующие тесты быстро запускают контейнеры
- Параллельное выполнение тестов ускоряет процесс
Сравнение подходов
| Подход | Плюсы | Минусы |
|---|---|---|
| Testcontainers | Изолировано, воспроизводимо, реальная БД | Медленнее in-memory |
| H2/In-Memory БД | Быстро | Не реальная БД, могут быть отличия |
| Mock БД | Очень быстро | Не тестируем реальную логику БД |
| Реальная БД | Реальное окружение | Зависит от состояния, медленно, конфликты |
Testcontainers это лучший компромисс между скоростью и реалистичностью тестирования.