programing

여러 Spring Boot 간에 테스트컨테이너를 재사용하는 방법테스트?

skycolor 2023. 3. 18. 08:24
반응형

여러 Spring Boot 간에 테스트컨테이너를 재사용하는 방법테스트?

Spring Boot에서 Test Containers를 사용하여 다음과 같은 저장소의 유닛 테스트를 실행하고 있습니다.

@Testcontainers
@ExtendWith(SpringExtension.class)
@ActiveProfiles("itest")
@SpringBootTest(classes = RouteTestingCheapRouteDetector.class)
@ContextConfiguration(initializers = AlwaysFailingRouteRepositoryShould.Initializer.class)
@TestExecutionListeners(listeners = DependencyInjectionTestExecutionListener.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Tag("docker")
@Tag("database")
class AlwaysFailingRouteRepositoryShould {

  @SuppressWarnings("rawtypes")
  @Container
  private static final PostgreSQLContainer database =
      new PostgreSQLContainer("postgres:9.6")
          .withDatabaseName("database")
          .withUsername("postgres")
          .withPassword("postgres");

하지만 지금은 14개의 테스트가 있으며 매번 테스트가 실행될 때마다 Postgres의 새로운 인스턴스가 가속됩니다.모든 테스트에서 동일한 인스턴스를 재사용할 수 있습니까?모든 테스트가 새로운 애플리케이션을 시작하기 때문에 싱글턴 패턴은 도움이 되지 않습니다.

도 ★★★★★★★★★★★★★★★★★★★★★★★★★testcontainers.reuse.enable=true.testcontainers.properties ★★★★★★★★★★★★★★★★★」.withReuse(true)을 사용법

주피터 JUnit은 수 .@Container재사용 가능한 컨테이너를 원할 경우.이 주석을 사용하면 각 테스트용기가 중지됩니다.

필요한 것은 싱글톤 컨테이너 접근법이며, 예를 들어 다음과 같이 사용합니다. @BeforeAll컨테이너를 기동합니다., 「 」를 가지고 있어도, 「 」가 됩니다..start()에서 Testcontainer를 을 선택한 는 새 .withReuse(true) 및 항목에서 사용할 수 있습니다..testcontainers.properties디렉토리의 : "파일":

testcontainers.reuse.enable=true

간단한 예는 다음과 같습니다.

@SpringBootTest
public class SomeIT {

  public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
    withReuse(true);

  @BeforeAll
  public static void beforeAll() {
    postgreSQLContainer.start();
  }

  @Test
  public void test() {

  }

}

기타 통합 테스트:

@SpringBootTest
public class SecondIT {

  public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
    withReuse(true);

  @BeforeAll
  public static void beforeAll() {
    postgreSQLContainer.start();
  }

  @Test
  public void secondTest() {

  }

}

현재 이에 대한 문서를 추가하는 PR이 있습니다.

테스트 용기로 용기를 재사용하는 방법을 자세히 설명하는 블로그 투고를 작성했습니다.

싱글톤 패턴으로 진행하기로 결정한 경우, "JDBC URL 체계를 통해 시작된 데이터베이스 컨테이너"의 경고에 유의하십시오.싱글톤 패턴을 사용했는데도 항상 다른 포트에 매핑된 추가 컨테이너가 생성된다는 것을 알아차릴 때까지 몇 시간이 걸렸습니다.

를 들어, JDBC(호스트리스) URI는 사용하지 말아 주세요.jdbc:tc:postgresql:<image-tag>:///<databasename>singleton 패턴을 사용합니다.

인정된 답변은 훌륭하지만 문제는 각 통합 테스트에 대해 구성(작성, 시작 등)을 반복해야 한다는 것입니다.보다 적은 코드 행으로 심플한 설정을 실시하는 것이 좋습니다.클린버전은 JUnit 5 확장자를 사용하는 것 같아요.

이렇게 해서 문제를 풀었어요.아래 샘플은 MariaDB 컨테이너를 사용하지만 이 개념은 모든 사용자에게 적용됩니다.

  1. 컨테이너 구성 홀딩 클래스를 만듭니다.
public class AppMariaDBContainer extends MariaDBContainer<AppMariaDBContainer> {

    private static final String IMAGE_VERSION = "mariadb:10.5";
    private static final String DATABASE_NAME = "my-db";
    private static final String USERNAME = "user";
    private static final String PASSWORD = "strong-password";

    public static AppMariaDBContainer container = new AppMariaDBContainer()
            .withDatabaseName(DATABASE_NAME)
            .withUsername(USERNAME)
            .withPassword(PASSWORD);

    public AppMariaDBContainer() {
        super(IMAGE_VERSION);
    }

}
  1. 를 만들고 합니다.DataSource에 따라 :" " " " 라요라라 。
public class DatabaseSetupExtension implements BeforeAllCallback {

    @Override
    public void beforeAll(ExtensionContext context) {
        AppMariaDBContainer.container.start();
        updateDataSourceProps(AppMariaDBContainer.container);
        //migration logic here (if needed)
    }

    private void updateDataSourceProps(AppMariaDBContainer container) {
        System.setProperty("spring.datasource.url", container.getJdbcUrl());
        System.setProperty("spring.datasource.username", container.getUsername());
        System.setProperty("spring.datasource.password", container.getPassword());
    }

}
  1. 더하다@ExtendWith당신의 시험반으로
@SpringBootTest
@ExtendWith(MariaDBSetupExtension.class)
class ApplicationIntegrationTests {

    @Test
    void someTest() {
    }

}

다른 테스트

@SpringBootTest
@ExtendWith(MariaDBSetupExtension.class)
class AnotherIntegrationTests {

    @Test
    void anotherTest() {
    }

}

싱글톤 컨테이너 또는 재사용 가능한 컨테이너를 사용하는 것이 가능한 해결책이지만, 컨테이너의 라이프 사이클을 애플리케이션 컨텍스트의 라이프 사이클에 적용하지 않기 때문에 둘 다 그다지 이상적이지 않습니다.

단, 컨테이너를 어플리케이션콘텍스트의 라이프 사이클까지 확장하려면ContextCustomizerFactory블로그 투고에 좀 더 자세히 써놨어요.

테스트 사용 시:

@Slf4j
@SpringBootTest
@EnabledPostgresTestContainer
class DemoApplicationTest {

    @Test
    void contextLoads() {
        log.info("Hello world");
    }

}

그런 다음 에서 주석을 활성화합니다.META-INF/spring.factories:

org.springframework.test.context.ContextCustomizerFactory=\
  com.logarithmicwhale.demo.EnablePostgresTestContainerContextCustomizerFactory

다음과 같이 구현할 수 있습니다.

public class EnablePostgresTestContainerContextCustomizerFactory implements ContextCustomizerFactory {

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface EnabledPostgresTestContainer {
    }

    @Override
    public ContextCustomizer createContextCustomizer(Class<?> testClass,
            List<ContextConfigurationAttributes> configAttributes) {
        if (!(AnnotatedElementUtils.hasAnnotation(testClass, EnabledPostgresTestContainer.class))) {
            return null;
        }
        return new PostgresTestContainerContextCustomizer();
    }

    @EqualsAndHashCode // See ContextCustomizer java doc
    private static class PostgresTestContainerContextCustomizer implements ContextCustomizer {

        private static final DockerImageName image = DockerImageName
                .parse("postgres")
                .withTag("14.1");

        @Override
        public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
            var postgresContainer = new PostgreSQLContainer<>(image);
            postgresContainer.start();
            var properties = Map.<String, Object>of(
                    "spring.datasource.url", postgresContainer.getJdbcUrl(),
                    "spring.datasource.username", postgresContainer.getUsername(),
                    "spring.datasource.password", postgresContainer.getPassword(),
                    // Prevent any in memory db from replacing the data source
                    // See @AutoConfigureTestDatabase
                    "spring.test.database.replace", "NONE"
            );
            var propertySource = new MapPropertySource("PostgresContainer Test Properties", properties);
            context.getEnvironment().getPropertySources().addFirst(propertySource);
        }

    }

}

어떻게 된 건지 모르겠어@Testcontainers효과는 있지만 수업당 효과가 있을 것 같습니다.

싱글톤 패턴에 설명된 대로 싱글톤을 정전기 상태로 만들어 신호기 홀더에서 모든 테스트에서 가져오기만 하면 됩니다. 모든 테스트 클래스에서 정의하지 마십시오.

언급URL : https://stackoverflow.com/questions/62425598/how-to-reuse-testcontainers-between-multiple-springboottests

반응형