JUnit 5 и наследование с различными расширениями для тестирования интеграции Spring Boot с помощью TestContainers

#java #spring-boot #integration-testing #junit5 #testcontainers

Вопрос:

Введение: Наш продукт должен иметь тесты интеграции для 3 различных баз данных:

  1. Oracle
  2. Postgres
  3. MSSQL

Мы используем Spring Boot в качестве нашей платформы и тестовых компонентов для запуска баз данных, упомянутых выше.

Проблема: Нам нужно выполнить одни и те же тесты для каждого контейнера (базы данных).

После долгих поисков в сети единственным способом, который я мог придумать, было использование базового класса, в котором мы пишем все тестовые случаи и для каждого контейнера, мы создаем класс, который наследуется от базового класса, и мы переопределяем метод и аннотируем его с помощью @Test.

Ниже в коде вы найдете одно расширение JUnit5 для Postgres, которое запускает TestContainer, базовый тестовый класс и тестовый класс, который расширяется из расширения Postgres, запускает контекст приложения Spring и запускает тесты из базового класса.

Код:

 import com.company.itest.AutoConfig;
import com.company.itest.BaseIntegrationTest;
import com.company.itest.db.mssql.MSSqlTest;
import com.company.itest.db.oracle.OracleTest;
import com.company.itest.db.postgres.PostgresTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

public class TestTheTest extends BaseIntegrationTest {
  public void contextLoads() {
    Assertions.assertEquals(1, 1);
  }
  public void contextLoads2() {
    Assertions.assertNotEquals(1, 2);
  }
}


@SpringBootTest(
    classes = AutoConfig.class,
    webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@PostgresTest
class TestPostgres extends TestTheTest {
  @Test
  public void contextLoads() {
    super.contextLoads();
  }
  @Test
  public void contextLoads2() {
    super.contextLoads2();
  }
}


import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.PostgreSQLContainer;

public class PostgresqlTestContainersExtension implements BeforeAllCallback, AfterAllCallback {

  private final Logger log = LoggerFactory.getLogger(PostgresqlTestContainersExtension.class);

  private PostgreSQLContainer<?> postgres;

  @Override
  public void beforeAll(ExtensionContext context) {
    log.info("Setting up postgres container");
    postgres = new PostgreSQLContainer<>("postgres:13").withReuse(true);

    postgres.start();
    System.setProperty("spring.datasource.url", postgres.getJdbcUrl());
    System.setProperty("spring.datasource.username", postgres.getUsername());
    System.setProperty("spring.datasource.password", postgres.getPassword());
  }

  @Override
  public void afterAll(ExtensionContext context) {
    postgres.stop();
  }
}



package com.company.itest.db.postgres;

import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@ExtendWith(SpringExtension.class)
@ExtendWith({PostgresqlTestContainersExtension.class})
@Testcontainers
public @interface PostgresTest {}
 

Вопрос:

Как я могу создать один тестовый класс JUnit, а затем повторно запустить его с другим расширением JUnit5, не выполняя этот полиморфизм?

Комментарии:

1. Вы могли бы реализовать интерфейс с тестами в методах по умолчанию вместо расширения суперкласса. Однако это все еще полиморфный подход. Для небольшого числа вариантов, таких как 3 разные базы данных, я нахожу этот подход приемлемым.

Ответ №1:

Если вы используете maven, вы можете попробовать создать другой профиль для каждой бд