JavaRush /Курси /Модуль 5. Spring /Лекція 268: Використання Testcontainers для інтеграційног...

Лекція 268: Використання Testcontainers для інтеграційного тестування з реальними базами даних

Модуль 5. Spring
Рівень 21 , Лекція 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! У наступних лекціях продовжимо досліджувати мікросервіси і інші інструменти тестування.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ