문제
JUnit과 Mockito를 사용해서 테스트를 하던 중 static 메서드를 mocking해야 하는 상황이 생겼다.
테스트하고 있던 부분은 JWT 토큰을 생성하고 검증하는 로직으로
여러 곳에서 호출해서 쓰인다고 생각해서 static 메서드로 만들고 common 패키지에 위치시켰다.
public class JwtUtil {
public static void verifyToken(String jwtToken) {
JWT.require(Algorithm.HMAC512(JWT_SECRET)).build().verify(jwtToken);
}
public static String createToken(Long userId, String email) {
return JWT.create()
.withClaim("id", userId)
.sign(Algorithm.HMAC512(JWT_SECRET));
}
}
아래 테스트를 해보면 실패한다.
static 메서드는 메모리에 올라갈 때 생성되기 때문에
아래와 같이 런타임에 mock을 하면 안 된다.
@ExtendWith(MockitoExtension.class)
public class UserControllerTest
@Mock
private JwtUtil jwtUtil;
@Test
@DisplayName("로그인 컨트롤러 성공 테스트")
void loginSuccessTest() throws Exception {
given(jwtUtil.createToken(1L, "aaa@naver.com"))
.willReturn("token");
}
}


해결
mockito-inline 사용하기
기존에는 mock 객체를 만들기 위해서 SubclassByteBuddyMockMaker를 사용했고
SubclassByteBuddyMockMaker는 상속을 사용해서 mock 객체를 만들었다.
mockito-inline을 의존성으로 등록하면 mock 객체를 만들때 InlineByteBuddyMockMaker를 사용하게 된다.
InlineByteBuddyMockMaker는 바이트코드 조작을 통해 mock 객체를 만들어주는데
이를 사용하면 static 메서드를 mocking 할 수 있다.
@ExtendWith(MockitoExtension.class)
public class UserControllerTest
@BeforeAll
public static void beforeAll() {
mockStatic(JwtUtil.class);
}
@Test
@DisplayName("로그인 컨트롤러 성공 테스트")
void loginSuccessTest() throws Exception {
given(JwtUtil.createToken(1L, "aaa@naver.com"))
.willReturn("token");
}
}
Bean으로 등록하기
static 메서드를 사용하지 말고 빈으로 등록해서 사용해서 해결할 수도 있다.
@Component
public class TokenProvider {
public void verifyToken(String jwtToken) {
JWT.require(Algorithm.HMAC512(JWT_SECRET)).build().verify(jwtToken);
}
public String createToken(Long userId, String email) {
return JWT.create()
.withClaim("id", userId)
.sign(Algorithm.HMAC512(JWT_SECRET));
}
}
참고
mockito v.5.0.0부터 mock 객체를 만들때
기본적으로 InlineByteBuddyMockMaker를 사용하는 것으로 바뀌었기 때문에
mockito-inline을 추가적으로 의존할 필요가 없어졌다.

'에러 해결' 카테고리의 다른 글
| [문제 해결] spring cloud starter aws 라이브러리 의존할 때 발생하는 에러를 알아보자 (1) | 2024.10.20 |
|---|---|
| [문제 해결] 역직렬화 과정에서 발생하는 문제를 해결해보자 (1) | 2023.12.23 |