ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Testcontainers, 컨테이너 정보를 스프링 테스트에서 참조하기
    백기선(인프런 강의)/더 자바, 애플리케이션을 테스트하는 다양한 방법 2020. 6. 7. 12:42
    반응형

    @ContextConfiguration

    • 스프링이 제공하는 애노테이션으로, 스프링 테스트 컨텍스트가 사용할 설정 파일 또는 컨텍스트를 커스터마이징할 수 있는 방법을 제공한다.

     

    ApplicationContextInitializer

    • 스프링 ApplicationContext를 프로그래밍으로 초기화 할 때 사용할 수 있는 콜백 인터페이스로, 특정 프로파일을 활성화 하거나, 프로퍼티 소스를 추가하는 등의 작업을 할 수 있다.

     

    TestPropertyValues

    • 테스트용 프로퍼티 소스를 정의할 때 사용한다.

     

    Environment

    • 스프링 핵심 API로, 프로퍼티와 프로파일을 담당한다.

     

    전체 흐름

    1. Testcontainer를 사용해서 컨테이너 생성
    2. ApplicationContextInitializer를 구현하여 생선된 컨테이너에서 정보를 축출하여 Environment에 넣어준다.
    3. @ContextConfiguration을 사용해서 ApplicationContextInitializer 구현체를 등록한다.
    4. 테스트 코드에서 Environment, @Value, @ConfigurationProperties 등 다양한 방법으로 해당 프로퍼티를 사용한다.

     

     

    전체적인 코드

    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    import static org.junit.jupiter.api.Assertions.assertNull;
    import static org.mockito.BDDMockito.given;
    import static org.mockito.BDDMockito.then;
    import static org.mockito.Mockito.times;
    
    import java.util.Optional;
    
    import org.junit.jupiter.api.BeforeAll;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.Mock;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.util.TestPropertyValues;
    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.test.context.ActiveProfiles;
    import org.springframework.test.context.ContextConfiguration;
    import org.testcontainers.containers.GenericContainer;
    import org.testcontainers.containers.output.Slf4jLogConsumer;
    import org.testcontainers.junit.jupiter.Container;
    import org.testcontainers.junit.jupiter.Testcontainers;
    
    import lombok.extern.slf4j.Slf4j;
    import me.whiteship.inflearnthejavatest.domain.Member;
    import me.whiteship.inflearnthejavatest.domain.Study;
    import me.whiteship.inflearnthejavatest.member.MemberService;
    
    @SpringBootTest
    @ExtendWith(MockitoExtension.class)
    @ActiveProfiles("test")
    @Testcontainers
    @Slf4j
    @ContextConfiguration(initializers = StudyServiceTest.ContainerPropertyInitializer.class)
    class StudyServiceTest {
    
        @Mock MemberService memberService;
    
        @Autowired StudyRepository studyRepository;
    
        @Value("${container.port}") int port;
        
        static Logger log = LoggerFactory.getLogger(StudyServiceTest.class);
    
        @Container
        static GenericContainer postgreSQLContainer = new GenericContainer("postgres")
                .withExposedPorts(5432)
                .withEnv("POSTGRES_DB", "studytest");
    
        @BeforeAll
        static void beforeAll() {
            Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(log);
            postgreSQLContainer.followOutput(logConsumer);
        }
    
        @BeforeEach
        void beforeEach() {
            System.out.println("===========");
            System.out.println(port);
            studyRepository.deleteAll();
        }
    
        @Test
        void createNewStudy() {
            // Given
            StudyService studyService = new StudyService(memberService, studyRepository);
            assertNotNull(studyService);
    
            Member member = new Member();
            member.setId(1L);
            member.setEmail("rlawls1991@email.com");
    
            Study study = new Study(10, "테스트");
    
            given(memberService.findById(1L)).willReturn(Optional.of(member));
    
            // When
            studyService.createNewStudy(1L, study);
    
            // Then
            assertEquals(1L, study.getOwnerId());
            then(memberService).should(times(1)).notify(study);
            then(memberService).shouldHaveNoMoreInteractions();
        }
    
        @DisplayName("다른 사용자가 볼 수 있도록 스터디를 공개한다.")
        @Test
        void openStudy() {
            // Given
            StudyService studyService = new StudyService(memberService, studyRepository);
            Study study = new Study(10, "더 자바, 테스트");
            assertNull(study.getOpenedDateTime());
    
            // When
            studyService.openStudy(study);
    
            // Then
            assertEquals(StudyStatus.OPENED, study.getStatus());
            assertNotNull(study.getOpenedDateTime());
            then(memberService).should().notify(study);
        }
    
        static class ContainerPropertyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
            @Override
            public void initialize(ConfigurableApplicationContext context) {
                TestPropertyValues.of("container.port=" + postgreSQLContainer.getMappedPort(5432))
                        .applyTo(context.getEnvironment());
            }
        }
    
    }
    반응형
Designed by Tistory.