Logo

dev-resources.site

for different kinds of informations.

Как подружить котиков, слонов и китов: тестирование Spring-приложений с Testcontainers 🐱🐘🐋

Published at
12/1/2024
Categories
java
beginners
webdev
rest
Author
easycat
Categories
4 categories in total
java
open
beginners
open
webdev
open
rest
open
Author
7 person written this
easycat
open
Как подружить котиков, слонов и китов: тестирование Spring-приложений с Testcontainers 🐱🐘🐋

Когда речь идет о тестировании Spring-приложений, нам часто приходится решать, как эмулировать реальные компоненты и внешние сервисы, чтобы тесты были как можно более похожи на реальную работу приложения. Но вот где всё становится интересным: мы будем использовать Testcontainers для эмуляции наших зависимостей и контейнеров. И это будет весело! Приготовьтесь познакомиться с котиками, слонами и китами, которые помогут вам на пути к стабильным и качественным тестам!

Что такое Testcontainers и зачем нам котики, слоны и киты?

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

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

Почему Docker нам нужен?
Docker позволяет создать временную базу данных, не занимая много места на компьютере.
Testcontainers автоматически запустит нужную нам базу данных для тестов, а после тестов удалит её.
Вместо того чтобы вручную настраивать PostgreSQL, мы просто говорим Testcontainers: "Запусти контейнер с PostgreSQL", и всё готово!
Важно: Чтобы все это работало, у тебя должен быть установлен Docker. Без него контейнеры не смогут работать.

Установка Docker (если у тебя его нет)

Скачай и установи Docker Desktop с официального сайта.
Запусти Docker.

Настройка окружения с котиками и слонами

Для начала давайте настроим PostgreSQL (слона) с помощью Testcontainers. Представьте, что котик сидит за компьютером и готовится к работе, а слон подготавливает базу данных для тестов.
В нашем проекте нам нужны следующие зависимости:

<dependencies>
    <!-- Testcontainers для Docker -->
      <dependency>
          <groupId>org.testcontainers</groupId>
          <artifactId>postgresql</artifactId>
          <scope>test</scope>
      </dependency>

    <!-- Spring Boot Starter Web для работы с контроллерами -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- PostgreSQL Driver -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
    </dependency>

    <!-- Spring Boot Test для тестирования -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
       <groupId>org.testcontainers</groupId>
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
    </dependency>
</dependencies>

Enter fullscreen mode Exit fullscreen mode

Мы создадим контроллер, который будет управлять запросами к базе данных. Например, пусть это будет контроллер, который работает с сущностью Kitten , и при этом взаимодействует с базой данных PostgreSQL.

pgvscat

Пример контроллера:

@RestController
@RequestMapping("/kittens")
public class KittenController {

    private final KittenService kittenService;

    @Autowired
    public KittenController(KittenService kittenService) {
        this.kittenService = kittenService;
    }

    @GetMapping
    public List<Kitten> getKittens() {
        return kittenService.getAllKittens();
    }

    @PostMapping
    public Kitten addKitten(@RequestBody Kitten kitten) {
        return kittenService.addKitten(kitten);
    }
}

Enter fullscreen mode Exit fullscreen mode

Как видите, контроллер использует сервис KittenService, который, в свою очередь, обращается к репозиторию для получения и сохранения данных. А теперь давайте проверим, как все это работает, настроив окружение с Testcontainers.

Использование Testcontainers для запуска PostgreSQL

Чтобы эмулировать PostgreSQL в контейнере, нам нужно создать контейнер с PostgreSQL и указать его параметры для использования в тестах. Вместо того чтобы подключаться к реальной базе данных, мы запустим ее прямо в Docker-контейнере.

@Testcontainers
public class KittenControllerTest {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:14")
            .withDatabaseName("test_db")
            .withUsername("test")
            .withPassword("test");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @BeforeAll
    public static void beforeAll() {
        postgres.start(); //стартуем контейнер с Postgres
    }

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void testGetKittens() {
        // Тестируем GET-запрос на получение котиков
        ResponseEntity<List<Kitten>> response = restTemplate.exchange("/kittens", HttpMethod.GET, null,
                new ParameterizedTypeReference<List<Kitten>>() {});
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertTrue(response.getBody().size() > 0);
    }

    @Test
    void testAddKitten() {
        // Тестируем POST-запрос на добавление нового котика
        Kitten newKitten = new Kitten("Fluffy", 1);
        ResponseEntity<Kitten> response = restTemplate.postForEntity("/kittens", newKitten, Kitten.class);
        assertEquals(HttpStatus.CREATED, response.getStatusCode());
        assertNotNull(response.getBody().getId());
    }
}

Enter fullscreen mode Exit fullscreen mode

Что происходит?

@Container: Аннотация от Testcontainers, которая говорит, что postgres — это контейнер, который нужно запустить перед тестами.
PostgreSQLContainer<?>: Специальный класс для создания контейнера PostgreSQL.
"postgres:14": Используем образ PostgreSQL версии 14.
withDatabaseName("test_db"): Создаем базу данных с именем test_db.
withUsername("test") и withPassword("test"): Указываем логин и пароль для подключения к базе данных.
Таким образом, этот код создает контейнер PostgreSQL, который автоматически запускается перед тестами и завершает работу после их окончания. Это исключает необходимость устанавливать PostgreSQL вручную.

Аннотация @DynamicPropertySource

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", postgres::getJdbcUrl);
    registry.add("spring.datasource.username", postgres::getUsername);
    registry.add("spring.datasource.password", postgres::getPassword);
}
Enter fullscreen mode Exit fullscreen mode

Аннотация @DynamicPropertySource, которая позволяет динамически задавать свойства приложения во время тестов.
DynamicPropertyRegistry registry: Хранилище для свойств, которое обновляется значениями из контейнера.
Зачем это нужно? Spring Boot-приложения используют application.properties для настройки подключения к базе данных. Вместо того чтобы прописывать их вручную, мы берем данные из контейнера:

spring.datasource.url: Получаем URL подключения к базе данных из контейнера.
spring.datasource.username и spring.datasource.password: Используем логин и пароль контейнера PostgreSQL.
Таким образом, приложение во время тестов подключается к базе данных в контейнере, а не к реальной базе данных. Это позволяет тестировать приложение в чистом изолированном окружении.

Как котики и слоны дружат с китами

Docker (кит) помогает нашему приложению Spring Boot запускать контейнеры с PostgreSQL (слон) для тестирования. Все это происходит благодаря Testcontainers, который автоматически запускает контейнеры и делает их доступными для вашего теста.

Когда вы запускаете тесты, Testcontainers подготавливает PostgreSQL контейнер с правильными настройками, а ваше приложение (котик) может без проблем взаимодействовать с ним. В этом процессе Docker (кит) берет на себя управление контейнерами и гарантирует, что все работает корректно.

docker

Преимущества использования Testcontainers

Изоляция тестов. Каждый тест запускает новый контейнер, что позволяет гарантировать чистоту данных и изоляцию.
Реальные данные. Вы тестируете ваше приложение на реальных сервисах и базах данных, а не на мокаемых компонентах.
Легкость в настройке. Не нужно вручную устанавливать и конфигурировать базы данных — все автоматически настраивается в контейнерах.

Заключение: Как котики, слоны и киты помогли нам

В итоге, когда котики (Spring Boot приложение), слоны (PostgreSQL) и киты (Docker) объединяются в одном тесте, мы получаем мощную комбинацию для тестирования реальных зависимостей. Вы больше не зависите от локальных баз данных или мока, а можете быть уверены, что ваше приложение будет работать с настоящими сервисами и базами данных. Это и есть секрет успеха качественных тестов в современных Spring-приложениях!

Теперь у нас есть полностью настроенное тестирование с Testcontainers, и все работает как часы, благодаря котикам, слонам и китам! 🐱🐘🐋

rest Article's
30 articles in total
Favicon
Best Practices for Securing REST APIs: Balancing Performance, Usability, and Security
Favicon
Learning REST APIs in JavaScript
Favicon
Validation in Spring REST Framework (SRF)
Favicon
API Design Best Practices in 2025: REST, GraphQL, and gRPC
Favicon
GraphQL vs REST: When to Choose Which for Your Node.js Backend
Favicon
REST VS SOAP
Favicon
Discover the 9 Best Open-Source Alternatives to Postman
Favicon
Building Robust REST Client with Quarkus: A Comprehensive Guide
Favicon
O que é REST API?
Favicon
Building Async APIs in ASP.NET Core - The Right Way
Favicon
Why Clear and Meaningful Status Codes Matter in Your REST API
Favicon
Understanding Request and Response Headers in REST APIs
Favicon
How Scale Changes Everything - The LiveAPI Perspective
Favicon
A Closer Look At API Docs Generated via LiveAPI's AI
Favicon
Quick and Easy: How to Test RESTful APIs in Java
Favicon
Understanding API Architectural Styles: REST, GraphQL, SOAP and More
Favicon
Implementing Pagination, Filtering, and Sorting in REST APIs
Favicon
REST In Peace
Favicon
Understanding HTTP Status Codes
Favicon
Musings Over What Makes LiveAPI Different (from Swagger Et Cetera)
Favicon
Introduction to APIs: Supercharging Your Web Development Journey
Favicon
An Innovative Way to Create REST APIs
Favicon
Best Practices for Developing and Integrating REST APIs into Web Applications
Favicon
Как подружить котиков, слонов и китов: тестирование Spring-приложений с Testcontainers 🐱🐘🐋
Favicon
Implementing Idempotent REST APIs in ASP.NET Core
Favicon
Understanding REST vs. GraphQL: Which One Should You Choose?
Favicon
Problem Details for ASP.NET Core APIs
Favicon
REST vs. GraphQL: Key Differences, Benefits, and Which One to Choose for Your Project
Favicon
REST vs. GraphQL: Choosing the Right API for Your Project
Favicon
Optimizing Your REST Assured Tests: Setting Default Host and Port, GET Requests, and Assertions

Featured ones: