Рубрики
Без рубрики

Добавление интеграционных тестов в Spring Boot с помощью тестовых контейнеров

Хорошее программное обеспечение всегда включает автоматизированные тесты для обнаружения ошибок во время создания и модификации… Помечено как spring boot, тестирование, testcontainers, java.

Хорошее программное обеспечение всегда включает в себя автоматизированные тесты для обнаружения ошибок во время создания и модификации кода. В этом руководстве интеграционные тесты будут добавлены в приложение Spring Boot , подключающееся к “реальной” базе данных с помощью библиотеки Testcontainers.

Фоны

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

Для этой цели существует библиотека Test containers для загрузки образа Docker именно той базы данных , которая используется разработчиком и позже в производстве. Чтобы написать интеграционный тест для нашего приложения, мы сначала добавляем зависимости.

testImplementation('org.testcontainers:junit-jupiter:1.15.0')
testImplementation('org.testcontainers:mysql:1.15.0')
testImplementation('org.springframework.boot:spring-boot-starter-test')

Зависимости build.gradle

Помимо spring-boot-starter-test нам нужны org.testcontainers:junit-jupiter , а также org.test containers ссылка на используемую нами базу данных. В нашем случае мы выбираем MySQL.

Запуск контекста приложения

Чтобы централизовать повторяющуюся логику наших тестовых классов, мы сначала создаем абстрактный базовый класс , от которого затем наследуются наши ИТ-классы. Первая версия этого класса выглядит следующим образом:

@SpringBootTest(classes = MyAppApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("it")
public abstract class BaseIT {

    @Autowired
    public TestRestTemplate restTemplate;

}

Первая версия BaseIT.java

Spring Boot обеспечивает очень хорошую поддержку интеграционного тестирования с помощью аннотации @SpringBootTest для загрузки полного контекста приложения . С помощью @ActiveProfiles мы определяем, что приложение запускается с профилем “это” . При необходимости мы можем использовать этот профиль для активации специальных настроек в нашем коде.

Установив переменную веб-среда в RANDOM_PORT приложение будет запущено через случайный (и доступный) порт. Это будет автоматически подхвачено TestRestTemplate при использовании его для отправки вызовов REST API нашего приложения – подробнее об этом позже.

Издевательство над базой данных

Теперь мы хотим настроить базу данных, доступную исключительно для наших тестов. Для этого мы расширяем ЕГО с помощью следующего фрагмента кода:

private static final MySQLContainer mySQLContainer;

static {
    mySQLContainer = (MySQLContainer)(new MySQLContainer("mysql:8.0")
            .withUsername("testcontainers")
            .withPassword("Testcontain3rs!")
            .withReuse(true));
    mySQLContainer.start();
}

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

Расширение нашего базового ИТ-класса с помощью настройки Testcontainers

В статическом разделе настраивается и запускается контейнер MySQL. Строка "mysql:8.0" определяет используемый образ Docker. В идеале это должно точно соответствовать версия, которая также используется в производстве. С параметром с повторным использованием(true) контейнер Docker не завершается автоматически в конце тестов, но доступен для повторного использования без более длительного периода ожидания. Иногда контейнер необходимо завершить вручную, чтобы полностью сбросить базу данных.

Чтобы разрешить повторное использование, файл //.test containers.properties должно быть расширено записью testcontainers.reuse.enable=true

В разделе после @DynamicPropertySource мы устанавливаем свойства на связываем контекст нашего приложения с базой данных контейнеров Docker . В зависимости от того, как мы инициализируем нашу схему базы данных – например, с помощью Flyway или Liquibase – это будет автоматически применено во время запуска контекста.

Запуск тестов

Сделав это, мы можем написать наш первый тестовый класс. Давайте предположим, что следующий @RestController уже существует. Служба, на которую ссылается ссылка, возвращает все записи, существующие в таблице “Test” .

@RestController
@RequestMapping(value = "/api/tests", produces = MediaType.APPLICATION_JSON_VALUE)
public class TestController {

    private final TestService testService;

    @Autowired
    public TestController(final TestService testService) {
        this.testService = testService;
    }

    @GetMapping
    public List getAllTests() {
        return testService.findAll();
    }

}

Тестовый контроллер нашего приложения Spring Boot

Теперь мы можем создать класс Testcontroller это расширяет наш абстрактный базовый класс. Метод тестирования отправляет запрос GET на существующую конечную точку, используя наш TestRestTemplate .

public class TestControllerIT extends BaseIT {

    @Test
    @Sql({"/data/clearAll.sql", "/data/testData.sql"})
    public void getAllTests_success() {
        final HttpEntity request = new HttpEntity<>(null, new HttpHeaders());
        final ResponseEntity> response = restTemplate.exchange(
                "/api/tests", HttpMethod.GET, request, new ParameterizedTypeReference<>() {});

        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertEquals(1, response.getBody().size());
        assertEquals((long)1000, response.getBody().get(0).getId());
    }

}

TestControllerIT нашего приложения Spring Boot

Несмотря на то, что наша схема базы данных уже инициализирована, нам все еще не хватает явных тестовых данных, необходимых для нашего теста. Для этого мы используем аннотацию Spring @Sql , который выполняет два скрипта и , таким образом , переводит нашу базу данных в известное состояние . В нашем случае теперь в тестовой таблице есть ровно одна запись, которую мы ожидаем в результате.

DELETE FROM test;

Удаление всех данных с помощью src/test/resources/data/clear All.sql

INSERT INTO test (
    id,
    test
) VALUES (
    1000,
    'Aenean pulvinar...'
);

Создайте единую запись таблицы с тестовыми данными.sql

С помощью RestTemplate.exchange(...) мы отправляем запрос GET в /api/tests . Функциональность в основном такая же, как мы уже знаем из класса Spring RestTemplate . Наш определенный запрос не отправляет никаких данных ( null ). Ответ десериализуется до типа List и в утверждениях мы проверяем, что Http Status и список соответствуют нашим ожиданиям.

Когда мы запускаем тест в первый раз, нам приходится немного подождать запуска контейнера Docker, в зависимости от нашей среды. Также может быть полезно предварительно кэшировать изображение с помощью docker pull mysql:8.0 , чтобы избежать проблем с загрузкой. Теперь наш тест должен пройти без ошибок.

Вывод

С помощью описанной настройки мы создали способ проверки поведения нашего приложения, включая базу данных с высокого уровня. Благодаря этому у нас есть очень хорошее дополнение к нашим модульным тестам. Test containers также предлагает поддержку других сервисов, таких как RabbitMQ, поэтому мы можем гибко расширять ЕГО по мере необходимости.

В профессиональном плане Boot предлагает возможность активировать тестовые контейнеры. Это инициализирует приложение Spring Boot, включающее описанную настройку, в зависимости от выбранной базы данных. Он также генерирует ИТ-классы и скрипты в соответствии с созданными таблицами и контроллерами.

» Смотрите Характеристики и цены

Дальнейшие чтения

Домашняя страница тестовых контейнеров Официальное руководство по тестированию приложений Spring Boot/| Концентратор Docker для поиска изображений Объяснение @Sql и @SqlMergeMode Где искать .test containers.properties

Оригинал: “https://dev.to/tleipzig/adding-integration-tests-in-spring-boot-with-testcontainers-ck7”