스프링부트 애플리케이션 테스트를 할 때 @Mock과 @MockBean을 사용할 때가 있다. 두 어노테이션 모두 모의 객체를 만들지만 용도가 조금씩 다르다.
간단하게 설명하면 비즈니스 로직을 단위 테스트할 때 @Mock을 사용한다. 애플리케이션 컨텍스트를 기반으로 하는 통합 테스트에서 빈을 모의 객체로 추가하거나 변경하는 경우에 @MockBean을 사용한다.
Using @Mock For Spring Boot Unit Tests
StockService라는 객체가 StockApiClient를 의존한다고 하자.
위 객체를 독립적으로 테스트하기 위해선 Junit과 Mockito가 필요하다.
StockService를 테스트할 때 의존 객체들을 mock으로 대체했다.
@InjectMock이 붙은 객체에 @Mock 어노테이션이 붙은 객체를 주입시킬 수 있다. 이는 스프링의 DI와는 다른 개념으로 Mockito에서 제공하는 유틸리티이다.
Using @MockBean to Add or Replace Beans with a Mock
이전에 설명한 @Mock과 @InjectMock은 스프링 프레임워크와 별개로 사용할 수 있었다면 @MockBean은 스프링 프레임워크에만 적용할 수 있다.
스프링부트의 도움 덕에 테스트를 위한 맞춤형 스프링 컨텍스트를 만들 수 있다. 전체 컨텍스트를 띄우거나(@SpringBootTest) 슬라이스 된 컨텍스트(@WebMvcTest 또는 @DataJpaTest)를 사용한다. 또한 모의 servlet 환경과 격리된 웹 계층을 테스트할 수 있다.
Spring TestContext는 런타임 동안의 Application Context와 유사하며 @AutoWired로 스프링 빈을 요청할 수 있다. 보통 TestContext는 빈의 부분집합만을 포함한다.(슬라이스 테스트)
Spring TestContext를 띄울 때 빈의 모든 의존성을 만족시켜야 한다. 스프링이 의존성을 주입할 수 있도록 컨텍스트 내에서 해당 인스턴스를 제공해야 한다. 그렇지 않으면 컨텍스트가 시작되지 않는다.
Spring TestContext를 커스터마이즈할 수 있기 때문에 원하는 실제 또는 모의 객체를 컨텍스트에 빈으로 관리할 수 있다.
예를 들어 아래와 같은 컨트롤러가 있다고 하자.
스프링부트의 @WebMvcTest를 사용하여 웹 계층과 관련된 빈만 포함하는 컨텍스트를 띄울 수 있다. 이때 StockController도 포함되어 있으므로 StockService 타입의 빈을 제공해야 한다. 그렇지 않으면 컨텍스트가 시작되지 않는다.
StockService의 실제 구현으로 빈을 등록할 수도 있지만 그렇게되면 StockService의 의존 객체들도 실제로 모두 빈으로 제공해야 한다. 이는 우리가 너무나 큰 의존성 계층을 제공해야 함을 의미한다.
또 웹 계층만을 테스트하기를 원하고 Stockservice 내부에서 일어나는 일에는 신경 쓰고 싶지 않다. 이러한 이유로 @MockBean을 사용하여 Stockservice는 모의 객체로 대체한다.
@MockBean 어노테이션은 스프링 테스트 컨텍스트 안에 있는 Stockservice 타입을 모의 객체로 변경한다.
이 어노테이션은 스프링 컨텍스트를 다루는 테스트에서 어디든지 사용할 수 있다.
통합 테스트에서도 @MockBean을 이용할 수 있다. 외부 인프라가 API를 호출할 때마다 요금이 부과된다고 하면 개발자는 해당 API를 부르는 객체를 mock으로 대체하여 통합 테스트를 진행할 수도 있다. (WireMock이 더 적합하긴 함)
General Advice on Using @MockBean for Your Spring Boot Tests
@MockBean을 너무 많이 사용하는 것도 좋지 않다. 작은 부분을 테스트하는 데 @SpringBootTest를 사용한 뒤 거의 모든 부분을 mocking 하는 사람들이 많다.
격리된 비즈니스 로직을 테스트하기 위해 전체 스프링 컨텍스트를 띄우는 것은 과도한 작업이다.
Junit과 Mockito를 활용한 단위 테스트를 많이 하도록 하자. 이는 테스트 속도를 향상시킨다.
하지만 단위 테스트가 일반적으로 많은 이점을 주지 않는 부분이 있다. 컨트롤러를 통한 엔드 포인트 테스트가 좋은 예다. 여기서는 @WebMvcTest와 @MockBean의 조합을 사용하는 것이 좋다.
@MockBean을 사용할 때마다 스프링은 mocking 된 타입의 실제 빈을 포함하는 기존 컨텍스트를 재사용할 수 없다. 즉 새로운 컨텍스트를 생성해야 하며 테스트 실행 시간이 늘어난다. 스프링의 컨텍스트 캐싱 메커니즘을 이해하면 빌드 시간을 크게 향상시킬 수 있다.
참고
https://rieckpil.de/difference-between-mock-and-mockbean-spring-boot-applications/
'스프링 > 테스트' 카테고리의 다른 글
TestContainer와 H2의 장점만 골라먹기 (1) | 2024.01.22 |
---|---|
@SpringBootTest (0) | 2022.04.30 |