← Назад к вопросам

Что такое библиотека Testcontainers?

2.2 Middle🔥 171 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Что такое библиотека 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 это лучший компромисс между скоростью и реалистичностью тестирования.

Что такое библиотека Testcontainers? | PrepBro