현재 프로젝트에서 애플리케이션 레이어 - 레포지토리 레이어 테스트코드를 작성할 때 @SpringBootTest
를 사용하고 있습니다. 그런데 @MockBean
이 있는 테스트 클래스마다 SpringApplicationContext 를 매번 띄우고 있는 상황이 발생하고 있었습니다.
왜 이런 상황이 발생하는지 기록하기 위해 이번 포스팅을 작성합니다.
공식문서에 따르면 Spring TestContext Framework는 Spring ApplicationContext 인스턴스 및 WebApplicationContext 인스턴스의 일관된 로딩과 해당 컨텍스트의 캐싱을 제공합니다.
이런 컨텍스트의 캐싱을 제공하는 이유는 최초로 스프링 컨텍스트를 띄우는 시간이 문제가 될 수 있기 때문입니다. 우리가 만들어 놓은 모든 빈들이 빈 컨테이너에 등록되고 스프링 부트가 제공해주는 모든 빈들이 등록되기 때문입니다. 이렇게 되면 모든 테스트를 실행하기 전에 컨텍스트를 띄우는 비용이 발생하게 되고 테스트 실행속도가 느려지게 됩니다.
그런데 똑똑한 스프링은 컨텍스트를 캐싱해두고 재사용하게 됩니다.
기본적으로 스프링 컨텍스트가 일단 로드되면 구성된 내용들은 각 테스트에 재사용되게 됩니다. 따라서 최초 설정 비용은 한 번만 발생하게 되는 것입니다.
그런데 왜 @MockBean
애노테이션이 있을 때 스프링 컨텍스트는 다시 띄워지는 것일까요?
공식문서에 따르면 테스트가 애플리케이션 컨텍스트를 손상시키고 다시 로드해야 하는 경우, (예: Bean 정의 또는 애플리케이션 객체의 상태를 수정) Spring TestContext Framework는 다음 테스트를 위해 구성을 다시 로드하고 애플리케이션 컨텍스트를 다시 빌드하도록 구성합니다.
즉 @MockBean
을 사용해 빈을 새롭게 정의했기 때문에 컨텍스트가 손상되었고 이를 감지한 스프링이 컨텍스트를 다시 띄우는 것이었습니다.
현재 각 테스트 클래스들은 필요한 빈들을 @Autowired
받고 있습니다.
@ApplicationTest
class AuthServiceTest {
@Autowired
private AuthService authService;
@Autowired
private SupportRepository supportRepository;
@MockBean
private NaverRequester naverRequester;
...
@ApplicationTest
public class CategoryServiceTest {
@Autowired
private CategoryService categoryService;
@Autowired
private SupportRepository supportRepository;
...
@ApplicationTest
class ItemServiceTest {
@MockBean
private S3Uploader s3Uploader;
@Autowired
private SupportRepository supportRepository;
@Autowired
private ItemService itemService;
...
이외에도 각 테스트 클래스들은 제어할 수 없는 것에 대해서는 @MockBean
처리를 해두고 있고 필요한 빈들은 @Autowired
를 통해 주입받고 있습니다.
어차피 제어할 수 없는 것들은 @MockBean
처리할 것이기 때문에 이를 공통 필드로 가지고 있는 클래스를 하나 생성한 후 각 테스트 클래스들은 공통 필드를 가지고 있는 클래스를 상속받도록 합니다.
@ApplicationTest
public class ApplicationTestSupport {
@MockBean
protected S3Uploader s3Uploader;
@MockBean
protected NaverRequester naverRequester;
@Autowired
protected SupportRepository supportRepository;
...
@ApplicationTest
class ItemServiceTest extends ApplicationTestSupport {
@Autowired
private ItemService itemService;
...
이렇게 스프링 컨텍스트가 띄워질 때 목처리할 빈들을 미리 만들어두게 되면서 스프링 애플리케이션 컨텍스트가 테스트 시에 한 번만 띄워지게 되었습니다!
https://docs.spring.io/spring-framework/reference/testing/integration.html#testing-ctx-management