대부분의 메서드와는 달리 static 메서드의 경우 mocking 하는 방법이 다르다.

예시를 통해 확인해보자.

아래 첫번째 코드는 jwt 토큰을 생성하는 메서드이고, 두번째 코드는 해당 토큰 생성 메서드를 사용하는 로그인 메서드이다.

JwtTokenUtil.java

public static String createToken(String userName, String secretKey, long expireTimeMs) {

    Claims claims = Jwts.claims();
    claims.put("userName", userName);

    return Jwts.builder()
            .setClaims(claims)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + expireTimeMs))
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
}

UserService.java

public UserLoginResponse login(String userName, String password) {
    // userName 존재 확인
    User user = userRepository.findByUserName(userName)
            .orElseThrow(() -> new AppException(ErrorCode.USERNAME_NOT_FOUND));

    // password 일치 여부 확인
    if(!encoder.matches(password, user.getPassword())) {
        throw new AppException(ErrorCode.INVALID_PASSWORD);
    }

    return new UserLoginResponse(JwtTokenUtil.createToken(userName, secretKey, expireTimeMs));
}

이 때, 일반 메서드처럼 mocking 했더니 다음과 같은 에러를 마주했다. void 메서드를 mocking 하듯이 해보기도 하고, 순서를 바꿔보기도 했으나 계속 같은 에러가 나왔다.

image

Mocking Static Methods With Mockito 에 보면 다음과 같은 설명이 있다.

image

이게 무슨 뜻이냐 하면, Mockito 3.4.0 부터 Mockito.mockStatic(Class<T> classToMock) 를 사용해 static 메서드 호출을 mock 할 수 있다는 내용이다.

추가적으로, 범위가 지정된 mock 객체에 대한 설명도 나와있다.

어쨌든, mockStatic() 의 매개변수로 static 메서드를 포함한 클래스를 넣어야, 테스트 할 때 static 메서드를 호출할 수 있다는 것으로 파악했다.

또한, 파라미터가 없는 static method의 경우엔 try-with-resources 문 안에서 객체를 만드는 것이 좋다고 한다.

MockedStatic javadoc.ioc의 설명에 보면 다음과 같은 설명이 있다.

image

그럼 적용해보자.


제일 먼저, 의존성 추가를 해줘야 한다.

당연하게도, mockito 3.4.0 버전 이상으로 추가해야 한다.

implementation 'org.mockito:mockito-inline:4.11.0'

만약, 의존성 추가 없이 진행하면 다음과 같은 에러가 발생한다.

image


다음으로, MockedStatic 객체를 선언한다.

MockedStatic<JwtTokenUtil> jwtTokenUtilMockedStatic = mockStatic(JwtTokenUtil.class);

그리고, 테스트 수행 후, .close() 를 통해 mocking을 종료한다.


로그인 성공 테스트의 전체 코드는 다음과 같다.

@Test
@DisplayName("로그인 성공")
public void login_success() {

    MockedStatic<JwtTokenUtil> jwtTokenUtilMockedStatic = mockStatic(JwtTokenUtil.class);

    given(userRepository.findByUserName(request.getUserName())).willReturn(Optional.of(user));
    given(encoder.matches(request.getPassword(), user.getPassword())).willReturn(true);
    given(JwtTokenUtil.createToken(request.getUserName(), secretKey, 500 * 60 * 60)).willReturn("token");

    UserLoginResponse response = userService.login(request.getUserName(), request.getPassword());

    assertThat(response.getJwt()).isEqualTo("token");

    jwtTokenUtilMockedStatic.close();
}


References

Tags:

Categories:

Date:

Leave a comment