Разделы портала

Онлайн-тренинги

.
Интеграционное тестирование базы данных с Testcontainers
29.11.2023 00:00

Автор: Куо Динг (Kwo Ding)
Оригинал статьи
Перевод: Ольга Алифанова

Как правило, для интеграционного тестирования базы данных используется расположенная в памяти база вроде H2. Это, однако, не гарантирует, что приложение правильно работает с боевой базой данных, которая в памяти не расположена. База данных H2 имеет множество перечисленных тут ограничений, а также ограничена в режимах совместимости (описано здесь). Это означает, что простой DDL-скрипт для реальной базы данных не всегда сработает на H2 в режиме совместимости.

Итак, расположенная в памяти база имеет ограничения, но как же проверить интеграцию с реальной базой данных? Или подключитесь к базе, похожей на боевую, или используйте Testcontainers, о чем мы сегодня и поговорим. Это позволит протестировать приложение на настоящей базе данных локально, подняв контейнер Docker с базой данных на лету.

Настроим его, используя MySQL в качестве примера.

Вначале добавим в проект все необходимые зависимости.

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-connector-j.version}</version>
</dependency>

Настройте ваше приложение, чтобы оно подключалось к контейнеру MySQL из Testcontainers. В Spring Boot-приложении это выглядит так:

spring:
datasource:
url: jdbc:tc:mysql:///test

И, наконец, задействуйте контейнер базы данных в тесте.

private final ContactClient client = new ContactClient(); 
private final Faker faker = Faker.instance();
private final MySQLContainer<?> mysql = new MySQLContainer<>();
@BeforeEach
void startContainer() {
mysql.start();
}
@Test
void shouldCreateContactWithRealDatabase() {
long contactId = faker.random().nextLong();
Contact contact = Contact.newBuilder()
.withId(contactId)
.withLastName(faker.name().lastName())
.withFirstName(faker.name().firstName())
.withPhone(faker.phoneNumber().cellPhone())
.build();
    client.createContact(contact)
.then()
.statusCode(201);
    Contact actualContact = client.getContact(contactId);
    assertThat(actualContact).isEqualTo(contact);
}

Примечание: этот тест основан на модели client-test.

Контейнер базы данных поднимется перед тестом и выключится после него.

Примечательные встроенные функции Testcontainers:

  • Можно настроить особый образ и тег Docker в конструкторе MySQLContainer (как и для любой другой базы данных).
  • Создание таблиц через DDL-скрипт можно указать при создании контейнера: new MySQLContainer<>().withInitScript("init.ddl").
  • Можно поддерживать контейнер активным, используя функцию “reuse” Testcontainers, чтобы проанализировать состояние реальной базы данных после теста. Создайте файл testcontainers.properties в пути к классу с содержанием testcontainers.reuse.enable=true

Заключение

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

Обсудить в форуме