문제상황
서비스 레이어의 단위 테스트 코드를 짜던 중, abstract class로 사용하던 SecurityUtils 의 getUserId() 라는 public static 메서드를 사용하고 싶었다.
실제로 실행이 되려면 시큐리티 관련 빈들이 등록되어야 하기에 Mockito를 사용하여 동작을 정의해주고 싶었다.
그러나 @Mock 를 사용하여 mock 객체를 주입받을 수 있는 다른 객체들과는 달리 static method를 사용하려면 별도의 작업이 필요했다.
static method에 mock 적용하기
사용 코드는 아래와 같다.
MockedStatic<SecurityContextUtils> mockSecurityUtils;
@BeforeEach
void beforeEach() {
mockSecurityUtils = mockStatic(SecurityContextUtils.class);
}
@AfterEach
void afterEach() {
mockSecurityUtils.close();
}
BDDMockito.given(SecurityContextUtils.getUserId()).willReturn(userID1);
MockedStatic<T> 객체를 BDDMockito 와 함께 사용하면 위와 같이 static method 의 동작을 정의할 수 있다.
궁금증
왜 mockStatic() 으로 선언하고 다시 close 해줘야할까?
mockStatic() 을 사용하면 해당 클래스에 모든 정적 메서드에 대해 쓰레드 로컬 mock 컨트롤러를 생성한다.
Spring Boot 는 기본적으로 쓰레드 풀을 사용하므로 쓰레드 로컬한 mock 컨트롤러는 별도의 처리를 해주지 않으면 해당 쓰레드를 다시 이용할 때 mock 컨트롤러를 대신 사용하게 될 수 있으므로 close 해주는 것이다.
SecurityContextUtils 에 대해 별 다른 처리를 해주지 않았는데 어떻게 동작하는 것일까?
BDDMockito.given 은 Mockito.when 을 내부적으로 사용하고, Mockito 는 내부적으로 쓰레드 로컬에 저장된 mockingProcess 를 사용하는데, 이 곳에 저장된 mock 컨트롤러를 실제 객체 대신 사용하는 방식으로 동작한다.