Spring Boot 및 Java 11/17이 포함된 테스트 컨테이너

테스트 컨테이너란 무엇입니까?



Testcontainers는 사용자가 Docker 이미지를 실행 및 관리하고 Java 코드에서 제어할 수 있도록 하는 JVM 라이브러리입니다.
통합 테스트는 외부 구성 요소를 실제 Docker 컨테이너로 추가로 실행합니다.

데이터베이스 - PostgreSQL을 Docker 이미지로 실행
모의 HTTP 서버 - MockServer 또는 WireMock Docker 이미지를 사용하는 HTTP 서비스
Redis - 실제 Redis를 Docker 이미지로 실행,
메시지 브로커 - RabbitMQ
AWS - S3, DynamoDB 등
Docker 이미지로 실행할 수 있는 기타 모든 애플리케이션

사용하는 방법?


  • 설정: Spring Boot 및 Junit 5
  • testImplementation "org.testcontainers:postgresql:1.16.2"및 testImplementation "org.testcontainers:junit-jupiter:1.16.2"에 대한 종속성
  • 그런 다음 통합 테스트가 컨테이너를 찾을 위치를 알 수 있도록 테스트 컨테이너를 시작하고 테스트 컨텍스트에 연결하는 몇 가지 배선()입니다.

  • 설정을 위한 추상 클래스의 예




    package com.test;
    
    import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.test.context.ActiveProfiles;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.support.TestPropertySourceUtils;
    import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
    import org.testcontainers.containers.PostgreSQLContainer;
    import org.testcontainers.ext.ScriptUtils;
    import org.testcontainers.jdbc.JdbcDatabaseDelegate;
    import org.testcontainers.junit.jupiter.Testcontainers;
    import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
    import org.testcontainers.shaded.com.fasterxml.jackson.databind.SerializationFeature;
    
    import java.util.Optional;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
    
    
    @Testcontainers
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {com.test.Application.class})
    @ActiveProfiles(AbstractBaseIntergrationTestConfiguration.ACTIVE_PROFILE_NAME_TEST)
    @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
    @ContextConfiguration(initializers = AbstractBaseIntergrationTestConfiguration.DockerPostgreDataSourceInitializer.class)
    public abstract class AbstractBaseIntergrationTestConfiguration {
    
        protected static final String JDBC_URL = "jdbc.url=";
        protected static final String JDBC_USERNAME = "jdbc.username=";
        protected static final String JDBC_PASSWORD = "jdbc.password=";
        protected static final String JDBC_DRIVER_CLASS_NAME_ORG_POSTGRESQL_DRIVER = "jdbc.driverClassName=org.postgresql.Driver";
        protected static final String ACTIVE_PROFILE_NAME_TEST = "TestContainerTests";
    
        //--
        public static PostgreSQLContainer<?> postgreDBContainer;
        protected ObjectMapper objectMapper = new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    
        static {
            // Init DB Script here
            postgreDBContainer = new PostgreSQLContainer<>(IntegrationTestConstants.POSTGRESQL_IMAGE);
            postgreDBContainer
                    .withInitScript(IntegrationTestConstants.INIT_DB_SCRIPT)
                    .withDatabaseName(IntegrationTestConstants.DB_NAME)
                    .withUsername(IntegrationTestConstants.DB_USERNAME)
                    .withPassword(IntegrationTestConstants.DB_PASSWORD);
    
            postgreDBContainer.start();
            var containerDelegate = new JdbcDatabaseDelegate(postgreDBContainer, "");
    
            // Adding Database scripts here
            ScriptUtils.runInitScript(containerDelegate, IntegrationTestConstants.MISSING_TABLES_SQL);
            ScriptUtils.runInitScript(containerDelegate, IntegrationTestConstants.SAMPLE_DATA_SQL);
        }
    
        // This class adds the DB properties to Testcontainers.
        public static class DockerPostgreDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
            @Override
            public void initialize(ConfigurableApplicationContext applicationContext) {
    
                TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
                        applicationContext,
                        JDBC_DRIVER_CLASS_NAME_ORG_POSTGRESQL_DRIVER,
                        JDBC_URL + postgreDBContainer.getJdbcUrl(),
                        JDBC_USERNAME + postgreDBContainer.getUsername(),
                        JDBC_PASSWORD + postgreDBContainer.getPassword()
                );
            }
        }
    }
    


    테스트를 작성하는 방법?




    @Test
    void checkIfUserExistInIdealCase() throws Exception {
    
      request.put("email", "[email protected]");
    
      final MockHttpServletRequestBuilder postObject = getPostRequestExecutorBuilder("http://localhost:8080/v1/checkemail/", Optional.empty());
      final MvcResult result = mockMvc.perform(postObject.content(request.toString())).andExpect(status().isOk()).andReturn();
      final String content = result.getResponse().getContentAsString();
    
      final SyncResponseDto responseDto = objectMapper.readValue(content, SyncResponseDto.class);
    
      assertThat(responseDto.getResponseReturnCode()).isEqualTo(ResponseReturnCode.USER\_EXIST);
    }
    


    장점


  • 통합 테스트를 오프라인으로 실행합니다.
  • 실제 구성 요소인 H2 데이터베이스 대신 PostgreSQL 데이터베이스에 대해 테스트를 실행합니다.
  • AWS 서비스를 모의할 수 있습니다.
  • PR을 올릴 때 개발자가 동시에 구현 및 테스트를 작성할 수 있습니다.

  • 단점


  • 주요 제한 사항은 테스트 클래스 간에 컨테이너를 재사용할 수 없다는 것입니다.
  • "하나 더"외부 종속성을 추가합니다.
  • 컨테이너를 시작하는 데 평소보다 약간 더 많은 시간이 소요됩니다. Postgres의 경우 4~5초, H2의 경우 0.5초입니다.
  • 로컬에서 실행할 때 로컬 시스템도 충분히 강력해야 합니다. ;)
  • 여러 컨테이너를 실행할 수 있으므로 더 많은 RAM, 더 많은 전력.

  • 참고문헌


  • Testcontainer
  • Test-Container Java
  • Testcontainer Example
  • 좋은 웹페이지 즐겨찾기