라떼군 이야기


Spring Boot 3.4.0에서 Deprecated된 @MockBean과 @MockBeans 대체 방법 (@MockitoBean 사용법)

Problem

Spring Boot 3.4.0으로 버전을 올리면서 기존 테스트 코드에서 사용하던 @MockBean@MockBeans 어노테이션이 Deprecated(사용 중단) 되었다는 경고가 발생합니다. 특히 여러 개의 Mock 객체를 한 번에 정의하기 위해 클래스 레벨에서 @MockBeans를 사용하거나 커스텀 어노테이션을 만들어 사용하던 경우, 새로운 @MockitoBean을 어떻게 적용해야 동일한 동작을 보장할 수 있는지 혼란스러울 수 있습니다. 단순히 어노테이션 이름만 바꾸면 컴파일 에러가 발생하거나 의도한 대로 동작하지 않을 수 있습니다.

Background

Spring Boot의 테스트 모듈은 오랫동안 Mockito와의 통합을 위해 @MockBean@SpyBean을 제공해 왔습니다. 이 어노테이션들은 Spring ApplicationContext 내의 실제 빈을 Mock 객체로 교체하여 단위 테스트나 통합 테스트를 용이하게 만들어줍니다. 하지만 Spring Boot 3.4.0부터는 이러한 기능을 제공하는 방식이 변경되어, 기존 어노테이션들이 Deprecated 되고 @MockitoBean@MockitoSpyBean이라는 새로운 표준이 도입되었습니다. 이는 프레임워크 내부 구조 개선 및 명확한 의도 표현을 위한 변화입니다.

Solution

Spring Boot 3.4.0 이상에서는 상황에 따라 다음과 같이 코드를 변경해야 합니다.

1. 필드 레벨 (Field Level) 변경

가장 흔한 케이스로, 테스트 클래스 내부의 필드에 Mock을 주입하는 경우입니다.

기존 (Deprecated):

@SpringBootTest
class MyServiceTest {

    @MockBean
    private ExternalService externalService;

    @SpyBean
    private InternalHelper internalHelper;
    
    // ... 테스트 코드
}

변경 후 (New):

@SpringBootTest
class MyServiceTest {

    // @MockBean -> @MockitoBean 으로 변경
    @MockitoBean
    private ExternalService externalService;

    // @SpyBean -> @MockitoSpyBean 으로 변경
    @MockitoSpyBean
    private InternalHelper internalHelper;

    // ... 테스트 코드
}

2. 클래스 레벨 (Class Level) 변경

질문자와 같이 여러 Mock을 클래스 상단에 정의하거나 커스텀 어노테이션을 만들 때 사용하던 @MockBeans의 대체 방법입니다. @MockitoBeantypes 속성을 사용합니다.

기존 (Deprecated):

// 여러 개의 빈을 Mock으로 등록하기 위해 @MockBeans 사용
@MockBeans({
    @MockBean(ServiceA.class), 
    @MockBean(ServiceB.class)
})
@SpringBootTest
class MyComplexTest {
    // ...
}

변경 후 (New):

// @MockitoBean의 types 속성에 클래스 배열을 전달하여 한 번에 등록
@MockitoBean(types = {ServiceA.class, ServiceB.class})
@SpringBootTest
class MyComplexTest {
    // ...
}

3. 커스텀 어노테이션 적용 예시

질문자의 상황처럼 공통 Mock 설정을 위한 커스텀 어노테이션을 만드는 경우입니다.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 기존 @MockBeans(...) 대신 아래와 같이 변경
@MockitoBean(types = {ServiceA.class, ServiceB.class, ServiceC.class})
public @interface MyMocksTest {

}

이제 @MyMocksTest를 테스트 클래스에 붙이면 정의된 서비스들이 자동으로 Mock 빈으로 컨텍스트에 등록됩니다.

Deep Dive

왜 변경되었나요?

Spring Boot 팀은 Mockito와의 통합 기능을 더 명확하게 하고, 프레임워크 내부의 구현 복잡도를 낮추기 위해 새로운 어노테이션을 도입했습니다. 기존 @MockBean은 이름이 일반적인 ‘Mock’을 의미하는지 ‘Mockito’를 의미하는지 모호할 수 있었으나, @MockitoBean은 Mockito 프레임워크를 사용함을 명시적으로 드러냅니다.

주의사항

  • 속성 이름 변경: 기존 @MockBean에서 사용하던 일부 속성들이 @MockitoBean에서는 지원되지 않거나 이름이 변경되었을 수 있으므로, 복잡한 설정을 사용 중이었다면 공식 문서를 확인해야 합니다.
  • 마이그레이션: 대규모 프로젝트의 경우 일일이 수정하기보다 OpenRewrite 같은 도구를 사용하여 자동화된 마이그레이션을 고려하는 것이 좋습니다.
  • 호환성: @MockBean은 현재 Deprecated 상태이지만 당분간은 작동할 것입니다. 하지만 향후 메이저 업데이트에서 완전히 제거될 수 있으므로, 3.4.0 업그레이드 시점에 맞춰 수정하는 것을 권장합니다.

Conclusion

Spring Boot 3.4.0에서 @MockBean@MockitoBean으로, @SpyBean@MockitoSpyBean으로 대체되었습니다. 특히 클래스 레벨에서 다수의 Mock을 정의할 때는 @MockitoBean(types = {...}) 형식을 사용하면 기존 @MockBeans의 기능을 완벽하게 대체할 수 있습니다. 최신 스프링 부트 버전을 사용한다면, 경고 메시지를 무시하지 말고 새로운 표준 어노테이션으로 전환하여 코드의 미래 호환성을 확보하세요.

Open to collaboration (협업 문의) Get in touch (연락하기) →