JavaRush /Курсы /Модуль 5. Spring /Лекция 268: Использование Testcontainers для интеграционн...

Лекция 268: Использование Testcontainers для интеграционного тестирования с реальными базами данных

Модуль 5. Spring
27 уровень , 7 лекция
Открыта

Когда речь идёт о микросервисах, базы данных играют важнейшую роль. Ваш код может выглядеть идеально, но если SQL-запросы не работают так, как надо, или структура базы данных отличается от ожиданий, результат может быть плачевным. А теперь представьте, что у вас в системе 10 микросервисов. Ошибки на этом уровне могут в буквальном смысле повергнуть систему в хаос.

Интеграционное тестирование с базой данных поможет:

  • Проверить, что SQL-запросы работают корректно.
  • Убедиться, что аннотации JPA и сущности настроены правильно.
  • Выполнить тесты миграций баз данных (например, Flyway или Liquibase).
  • Убедиться, что транзакции обрабатываются корректно.

Однако поднимать реальную базу данных для каждого тестирования – сложно и долго. Тут на сцену выходит Testcontainers.


Что такое Testcontainers?

Testcontainers — это Java-библиотека для написания тестов, использующих Docker-контейнеры. Она позволяет поднимать и уничтожать временные контейнеры для баз данных, брокеров сообщений, веб-серверов и других сервисов, прямо во время выполнения тестов. Красота заключается в том, что как только тесты запускаются, контейнеры поднимаются по необходимости, а после завершения тестирования автоматически уничтожаются.

Пример из жизни: представьте, что вы берёте машину в каршеринг. Вы используете её только тогда, когда это нужно, и сдаёте обратно. Testcontainers работает по аналогичной схеме с Docker-контейнерами для тестов.


Как работает Testcontainers?

  1. Вы указываете, какой контейнер нужно запустить (например, PostgreSQL).
  2. Контейнер поднимается перед тестом.
  3. Код теста подключается к контейнеру и тестирует взаимодействие.
  4. После завершения теста контейнер автоматически удаляется с вашей машины.

Основное преимущество: Нет зависимости от реальных баз данных и внешних сервисов. Всё изолировано.


Установка Testcontainers

Для начала добавим зависимости в pom.xml (если вы используете Maven):


<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>

Если вы используете Gradle, то добавляем:


testImplementation 'org.testcontainers:junit-jupiter:1.19.0'
testImplementation 'org.testcontainers:postgresql:1.19.0'

Кроме того, убедитесь, что у вас установлен Docker и он работает. Если вы используете Docker Desktop, то можно уже радоваться.


Ваш первый тест с Testcontainers

Начнём с создания самого простого теста. Мы поднимем контейнер PostgreSQL и проверим, что можем к нему подключиться:


import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;

import static org.junit.jupiter.api.Assertions.assertNotNull;

public class PostgresTest {

    @Test
    public void testPostgresContainer() {
        // Создаём PostgreSQL контейнер
        try (PostgreSQLContainer
    postgres = new PostgreSQLContainer<>("postgres:15.1")) {
            // Запускаем контейнер
            postgres.start();

            // Проверяем, что контейнер запущен, а URL подключения не пустой
            assertNotNull(postgres.getJdbcUrl());
            System.out.println("PostgreSQL запущен на " + postgres.getJdbcUrl());
        }
    }
}

Если вы запустите этот тест, Docker поднимет контейнер PostgreSQL, выполнит тест и уничтожит контейнер. Посмотрите в консоль: там должна появиться информация о запущенной базе данных.

Интеграция с Spring Data JPA

Теперь подключим Testcontainers к реальному приложению. Мы будем использовать Spring Boot и JPA.

1. Конфигурация Spring Boot

В файле application.properties укажите "заглушечные" параметры для базы данных (они будут переопределены Testcontainers на этапе тестирования):


spring.datasource.url=jdbc:tc:postgresql:15.1://localhost/testdb
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.hibernate.ddl-auto=update

Обратите внимание на формат jdbc:tc:postgresql:15.1://localhost/testdb. Testcontainers автоматически подтянет контейнер PostgreSQL указанной версии!

2. Создание сущности

Добавим сущность User:


import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    // геттеры и сеттеры
}

3. Создание репозитория

Создаём простой интерфейс репозитория:


import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

4. Тестирование репозитория с Testcontainers

Добавим тесты для проверки операций CRUD. Testcontainers сам создаст контейнер PostgreSQL при запуске тестов:


import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DataJpaTest
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void testSaveUser() {
        // Сохраняем нового пользователя
        User user = new User();
        user.setName("John Doe");
        User savedUser = userRepository.save(user);

        // Проверяем, что пользователь сохранился
        assertEquals("John Doe", savedUser.getName());
    }
}

Когда вы запустите этот тест, Testcontainers поднимет контейнер PostgreSQL, создаст базу данных testdb, а затем выполнит SQL-операции. По завершении контейнер будет автоматически уничтожен.


Преимущества Testcontainers

  1. Изоляция окружения: каждая тестовая база данных запускается в отдельном контейнере.
  2. Минимальная настройка: не нужно руками поднимать базы данных или удалять их после тестов.
  3. Реалистичность: вы тестируете код на реальной базе данных, а не на эмуляции.
  4. Поддержка множества баз данных и сервисов: например, MySQL, MongoDB, Redis, Kafka.

Типичные ошибки и особенности использования

  1. Ошибка "Docker not found". Убедитесь, что Docker запущен, и ваша среда разработки имеет к нему доступ.
  2. Медленные тесты. Поднятие контейнера занимает время. Используйте общие контейнеры для группы тестов, чтобы ускорить процесс.
  3. Утечки ресурсов. Не забывайте закрывать контейнеры после тестов, если вы запускаете их вручную (не автоуправляемые Testcontainers).

Где это пригодится?

  1. Разработка микросервисов: поднимаете реальную базу или брокер сообщений (Kafka, RabbitMQ) для тестов.
  2. Проверка миграций: убедитесь, что ваши Flyway-миграции работают на всех целевых базах.
  3. Собеседования: на вопрос "Как вы тестируете базы данных в своих проектах?" ваш ответ "Testcontainers" вызовет интерес и дополнительный плюс.

Теперь вы знаете, как Testcontainers позволяет вам поднимать реальное окружение для тестирования прямо из кода. Запустите тесты и почувствуйте магию изоляции Docker! В следующих лекциях мы продолжим исследовать микросервисы и другие инструменты тестирования.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ