kimyu0218
  • [spring] 설정 분리 (@SpringBootTest, @Profile, @ActiveProfiles, @TestPropertySource, @TestConfiguration)
    2024년 06월 18일 23시 57분 21초에 업로드 된 글입니다.
    작성자: @kimyu0218

    @SpringBootTest

    `@SpringBootTest`는 스프링 부트 어플리케이션의 통합 테스트를 위한 어노테이션이다. 전체 어플리케이션 컨텍스트를 로드하여 실제 어플리케이션과 동일한 환경에서 테스트를 진행할 수 있다.

    `@BootstrapWith(SpringBootTestContextBootstrapper.class)`은 테스트 컨텍스트를 부트스트랩하고 어플리케이션 컨텍스트를 로드한다.

    • `SpringBootTestContextBootstrapper` : `TestContextBootStrapper`를 상속하여 테스트 환경을 설정한다.
      1. 컨텍스트 로더로 `SpringBootContextLoader`를 사용한다.
      2. `@SpringBootApplication`을 사용하여 어플리케이션 컨텍스트를 초기화한다.
      3. 스프링 부트의 기본 설정 파일 `application.properties` 를 로드한다.
        1. `/config/application.properties`
        2. `/application.properties`
        3. `/src/main/resources/config/application.properties`
        4. `/src/main/resources/application.properties`
      4. 활성화된 프로파일이 있다면, 프로파일에 맞는 설정 파일 `application-[PROFILE].properties`을 추가적으로 로드한다.
      5. (`@SpringBootApplication`에 포함된) `@EnableAutoConfiguration` 및 `@ComponentScan`을 바탕으로 어플리케이션 컨텍스트를 초기화한다.
        • `@EnableAutoConfiguration`은 자동 구성, `@ComponentScan`은 명시적 빈을 등록한다.
        • 동일한 타입의 빈이 중복으로 정의되었다면, 명시적 빈이 우선한다.
    🤔 명시적 빈이 우선할 수 있는 이유 : `@ConditionalOn*`
    • `org.springframework.boot.autoconfigure`의 클래스에는 `@ConditionalOn*` 어노테이션이 붙어있다.
    • `@ConditionalOn*`은 특정 조건을 충족할 때 빈을 생성한다.
      • `@ConditionalOnBean` : 지정된 타입의 빈이 이미 컨텍스트에 존재할 때
      • `@ConditionalOnMissingBean` : 지정된 타입의 빈이 컨텍스트에 존재하지 않을 때
      • `@ConditionalOnClass` : 지정된 클래스가 classpath에 존재할 때
      • `@ConditionalOnMissingClass` : 지정된 클래스가 classpath에 존재하지 않을 때
      • `@ConditionalOnProperty` : 특정 속성의 값이 조건을 만족할 때
    💡 속성
    • `properties` : 테스트에 적용할 속성 지정
      • 개별 key-value 등록 (ex. `spring.datasource.url=[URL]`)
      • 속성 파일 위치 지정 (ex. `spring.config.location=classpath:[PROPERTY_FILE_PATH]`)
    • `classes` : 테스트에 사용할 자바 기반 설정 지정 (ex. `classes = { SpringConfig.class, SpringTestConfig.class })`)
    • `args` : 어플리케이션 인자 정의 (ex. `--server.port=8080`)

    @Profile

    `@Profile`은 특정 프로파일이 활성화되었을 때만 설정이나 빈이 컨텍스트에 등록되도록 한다. (클래스 레벨, 메서드 레벨모두 가능!) 이를 활용하여 개발, 테스트, 운영 환경에서 각각 다른 설정을 적용할 수 있다.

    @Configuration
    @Profile("dev")
    public class DevConfig { ... }
    
    @Configuration
    @Profile("prod")
    public class ProdConfig { ... }

     

    프로파일 활성화 

    `@ActiveProfiles`는 `org.springframework.test.context`에 속한 어노테이션으로, 테스트에서 특정 프로파일을 활성화할 때 사용한다.

    @ContextConfiguration
    @ActiveProfiles("dev")
    public class DevIntegrationTest { ... }
    
    @ContextConfiguration
    @ActiveProfiles("prod")
    public class ProdIntegrationTest { ... }
    💡 `org.springframework.test.context.ContextConfiguration`
    • 통합 테스트 시 어플리케이션 컨텍스트를 로드하고 구성한다.
    • `@ContextConfiguration(classes = SpringIntegrationTestConfig.class)`
    • 스프링 부트 어플리케이션의 전체 컨텍스트를 로드하지 않기 때문에 모든 빈이 로드되지 않을 수 있다. 이 경우 `@SpringBootTest`를 사용한다.
    🚨 `@ContextConfiguration`이 제대로 동작하지 않을 때 필요한 어노테이션
    • `@ExtendWith(SpringExtension.class)` : JUnit 5와 스프링 테스트 컨텍스트를 통합하여 테스트에서 스프링의 기능을 사용할 수 있다. (ex. 의존성 주입)
    • `@EnableAutoConfiguration` : 스프링 부트의 자동 설정을 활성화하여 classpath에 있는 설정 파일을 기반으로 스프링 빈을 자동으로 구성한다.
    • `@ComponentScan` : 지정된 패키지에서 컴포넌트를 스캔하고, 어플리케이션 컨텍스트에 등록한다.
    // 1. SpringBootTest ver.
    @SpringBootTest(classes = [JAVA_BASED_CONFIGURATION_CLASS], properties = "spring.config.location=classpath:[PROPERTY_FILE_PATH]")
    
    // 2. ContextConfiguration ver.
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = [JAVA_BASED_CONFIGURATION_CLASS])
    @TestPropertySource(locations = "classpath:[PROPERTY_FILE_PATH]")
    @EnableAutoConfiguration
    @ComponentScan(basePackages = "[BASE_PACKAGE]")
    
    // 3. SpringJUnitConfig ver.
    @SpringJUnitConfig([JAVA_BASED_CONFIGURATION_CLASS])
    @TestPropertySource(locations = "classpath:[PROPERTY_FILE_PATH]")
    @EnableAutoConfiguration
    @ComponentScan(basePackages = "[BASE_PACKAGE]")

     

    이외에도 `*.properties` 파일을 활용하여 `@AcitveProfiles` 없이도 프로파일을 지정할 수 있다.

    spring.profiles.active=dev

    @TestPropertySource

    특정 속성 파일이나 인라인 속성을 추가하여 테스트 환경에서 별도의 설정을 적용할 수 있도록 한다.

    • 속성 파일 위치 지정 : `locations = "classpath:[PROPERTY_FILE_PATH]"`
    • 인라인 속성 설정 : `properties = "[KEY]=[VALUE]"`
    ...
    @TestPropertySource(locations = "classpath:application-test.properties")
    class TestPropertySourceTest { ... }

    @TestConfiguration

    테스트 환경을 위한 추가적인 자바 기반 설정을 정의할 때 사용하는 어노테이션이다. 주로 테스트에서만 필요한 빈들을 정의하고 기존 구성 요소를 대체하기 위해 사용한다.

    @TestConfiguration
    public class TestConfig { 
      ...
      @Bean
      public TestBean testBean() { ... }
    }
    💡 `@Configuration`과 유사하지만 테스트 컨텍스트에만 적용된다는 차이가 있다. 

     

    `@SpringBootTest` `@Profile` `@ActiveProfiles` `@TestPropertySource` `@TestConfiguration`
    boot.test.context context.annotation test.context test.context boot.test.context
    클래스 레벨 클래스/메소드 레벨 클래스 레벨 클래스 레벨 클래스 레벨

    참고자료

    댓글