Spring | @TestConfiguration과 @Import

yeonk·2023년 4월 27일
5

spring & spring boot

목록 보기
6/10
post-thumbnail
post-custom-banner

개요


우아한테크코스 레벨2 웹 자동차 경주 미션을 진행하면서 @TestConfiguration을 사용하게 되어 내용을 정리해보려고 한다.





적용


해당 미션에서는 랜덤한 수를 반환하는 RandomStrategy를 사용하고 있다. 하지만 테스트 하기 위해서는 고정적인 값이 필요하기 때문에, 테스트 시 테스트용으로 작성한 FixedMovingStrategy를 사용해야한다.
어떻게 이미 컴포넌트로 등록된 MovingStrategy를 테스트에만 변경하여 적용할 수 있을까?

RacingCarController 에 테스트를 진행하고자 하며, 테스트를 위해 Controller 테스트 내부에 Config 클래스를 만들고 @TestConfiguration 애너테이션을 사용해 기존에 RandomStrategy를 사용하는 곳에 FixedMovingStrategy를 사용할 수 있도록 했다.



MovingStrategy

public interface MovingStrategy {

    int getRandomNumber();
}



RandomMovingStrategy

@Component
public class RandomMovingStrategy implements MovingStrategy {

    private final int MAX_MOVING_NUM = 9;
    private final Random random = new Random();

    @Override
    public int getRandomNumber() {
        return random.nextInt(MAX_MOVING_NUM);
    }
}



FixedMovingStrategy

public class FixedMovingStrategy implements MovingStrategy {

    @Override
    public int getRandomNumber() {
        return 5;
    }
}



RacingCarControllerTest

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RacingCarControllerTest {

    @LocalServerPort
    int port;

    @TestConfiguration
    static class RacingCarControllerTestConfig {
        @Bean
        MovingStrategy movingStrategy() {
            return new FixedMovingStrategy();
        }
    }
 }





위와 같이 구현했더니, 리뷰어님이 이후에 다른 테스트들이 추가되면 모두 필요한 공통 설정이 될 수 있으니 클래스 분리를 하는 것이 어떻겠냐고 제안주셨다.
해당 의견에 동의해서 기존에 RacingCarControllerTest 내부에 위치한 RacingCarControllerTestConfig를 외부로 분리하였다(TestConfig).



TestConfig

@TestConfiguration
public class TestConfig {
    @Bean
    MovingStrategy movingStrategy() {
        return new FixedMovingStrategy();
    }
}



그런데 클래스 분리를 하고 난 후에 테스트가 깨지는 문제가 발생했다. 설정한 FixedMovingStragtegy가 적용되지 않는 것 같았고,@Import를 사용하면 문제를 해결할 수 있음을 알아내었다.
@Import를 아래와 같이 붙여주었더니 잘 동작하였다.

RacingCarControllerTest

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Import({TestConfig.class})
class RacingCarControllerTest {
	// ... 테스트 코드
}

그럼 이제 @TestConfiguration@Import에 대해 알아보자.





@TestConfiguration


테스트를 할 때, 실제 애플리케이션 컨텍스트가 아닌 테스트용 configuration을 사용하고 싶을 수 있다. 이 때 @TestConfiguration을 사용할 수 있다.

공식 문서에서는 @TestConfiguration을 아래와 같이 설명하고 있다.

  • 테스트에 대한 추가적인 빈이나 커스텀을 정의하는 데 사용할 수 있는 @Configuration이다.

  • @Configuration 클래스와 달리 @TestConfiguration을 사용해도 @SpringBootConfiguration의 자동 감지를 방지하지 않는다.





@TestConfiguration을 사용하는 방법은 2가지이다.

  • 테스트 클래스에 static inner class를 만들어 빈을 @Autowire 하는 방법
@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {

    @TestConfiguration
    static class EmployeeServiceImplTestContextConfiguration {
        @Bean
        public EmployeeService employeeService() {
            return new EmployeeService() {
                // implement methods
            };
        }
    }

    @Autowired
    private EmployeeService employeeService;
}





  • Test용 configuration 클래스를 만들고, 사용할 테스트에 @Import를 사용해 명시해주는 방법
@TestConfiguration
public class EmployeeServiceImplTestContextConfiguration {
    
    @Bean
    public EmployeeService employeeService() {
        return new EmployeeService() { 
            // implement methods 
        };
    }
}
@RunWith(SpringRunner.class)
@Import(EmployeeServiceImplTestContextConfiguration.class)
public class EmployeeServiceImplIntegrationTest {

    @Autowired
    private EmployeeService employeeService;

    // remaining class code
}





@Import


@Import 애너테이션을 사용하면 특정 컴포넌트를 다른 configuration으로 import할 수 있다.

공식 문서에서는 @Import를 아래와 같이 설명하고 있다.

  • import할 하나 이상의 컴포넌트 클래스(일반적으로 @Configuration 클래스)를 명시한다.

  • Spring XMLImport와 같은 기능을 제공한다.

  • 가져온 @Configuration 클래스에서 선언된 @Bean 정의는 @Autowired 주입을 사용하여 액세스해야 한다. 빈 자체를 자동 와이어링하거나 빈을 선언하는 구성 클래스 인스턴스를 자동 와이어링할 수 있다.

  • XML 또는 @Configuration 이외의 리소스를 가져와야 하는 경우 @ImportResource 어노테이션을 대신 사용 한다.


해당 애너테이션을 사용할 때, 아래와 같이 여러 클래스를 import할수도 있다.

@Configuration
@Import({ DogConfig.class, CatConfig.class })
class MammalConfiguration {
}





참고 자료


Testing in Spring Boot
Annotation Interface TestConfiguration
Spring @Import Annotation
@Import in Spring
Annotation Type Import

post-custom-banner

3개의 댓글

comment-user-thumbnail
2023년 4월 27일

@TestConfiguration으로 처리하셨군요! 전략패턴을 사용하는 상황에서 빈 이름이 중복될 때에, 수동 빈 등록 말고 자동 빈 등록 상황에서도 해결할 수 있는 방법이 몇 가지 있더라구요. @Primary@Qualifier, 빈의 필드명 매칭 방법이 간단하게 있을 것 같네요 ㅎㅎㅎ

한편으로, @Import를 내가 원하는 빈들만 등록하고 싶을 때 사용해도 되나 궁금하던 참이었는데, 조이는 어떻게 생각하시는지 궁금합니다! 저는 보통 @MvcTest@JdbcTest에서 필요한 것들만 빈으로 올리고 싶을 때 사용하곤 했었는데 Configuration 클래스를 Import할 때에만 사용하는 것이 좋은지 궁금해요 ㅎㅎㅎ

1개의 답글