문제 발생
프로젝트 테스트 코드를 작성 후 gradle test로 모든 테스트를 실행시키는데 실패를 했습니다.
분명히 클래스 하나하나 테스트에는 문제가 없었는데 전체 테스트를 돌릴 때만 실패를 했습니다.
이 상태에서 다시 gradle test를 하면 실패한 테스트부터 실행하는데 신기하게도 모든 테스트가 통과되었습니다.
일시적인 오류로 실패를 했나싶어 다시 테스트를 돌렸지만 실패를 했고 원인을 찾아봤습니다.
우선 UserFactoryTest만 실패를 하고 원인은 값이 제대로 들어가지 않아 null 인 점, 테스트 순서에 따라 결과가 달라지는 점을 고려해 혹시 다른 테스트에서 UserFactory를 사용하는 부분에서 문제가 생기지 않았나 하며 다른 코드를 찾아봤습니다.
@Test
void OAuth2_로그인이_성공하면_LoginSuccessResponse_응답을_한다() throws ServletException, IOException {
mockUserFactory = mockStatic(UserFactory.class));
mockUserFactory
.when(() -> UserFactory.of(anyString(), anyMap()))
.thenReturn(User.builder().build());
when(userRepositoryOAuth2UserHandler.apply(any())).thenReturn(User.builder().build());
when(jwtProvider.createAccessToken(any())).thenReturn("accessToken");
when(jwtProvider.createRefreshToken(any())).thenReturn("refreshToken");
oAuth2LoginSuccessHandler.onAuthenticationSuccess(request, response,
createAuthentication());
assertAll(
() -> assertThat(response.getStatus()).isEqualTo(SC_OK),
() -> assertThat(response.getContentType()).isEqualTo(APPLICATION_JSON_VALUE),
() -> verify(objectMapper).writeValue(eq(response.getOutputStream()),
any(LoginSuccessResponse.class))
);
}
UserFactory 클래스는 User를 생성하는 Factory 클래스로 static 메서드만 존재하고 있습니다. 해당 클래스를 mockStatic를 이용해 mocking 하여 사용하고 있었습니다.
Mockito 문서에 따르면 mockStatic은 주어진 클래스 또는 인터페이스의 모든 정적 메서드에 대해 스레드-로컬(mock controller) 목 컨트롤러를 생성한다. 반환된 객체의 ScopedMock.close()메서드는 테스트 완료 시 호출되어야 합니다. 그렇지 않으면 모의 개체가 현재 스레드에서 활성 상태로 유지됩니다.라고 나와있습니다. mock 객체는 mockMaker가 Byte Buddy를 이용해 동적 프록시 객체를 생성합니다.
junit에서 모든 테스트는 단일 스레드에서 순차적으로 진행되는데, 사용 후 자원을 할당 해제하지 않아서 다른 테스트에서 사용하는 UserFactory가 mocking 된 상태로 사용되어 문제가 생긴 것이었습니다. UserFactoryTest가 먼저 진행됐을 때 문제가 발생하지 않는 이유도 위와 같은 내용 때문이었습니다.
해결
따라서 close() 메서드를 사용해 자원을 해제하거나 try-with-resources 문을 이용하면 문제가 해결됩니다.
close()
@Test
void OAuth2_로그인이_성공하면_LoginSuccessResponse_응답을_한다() throws ServletException, IOException {
mockUserFactory = mockStatic(UserFactory.class));
mockUserFactory
.when(() -> UserFactory.of(anyString(), anyMap()))
.thenReturn(User.builder().build());
when(userRepositoryOAuth2UserHandler.apply(any())).thenReturn(User.builder().build());
when(jwtProvider.createAccessToken(any())).thenReturn("accessToken");
when(jwtProvider.createRefreshToken(any())).thenReturn("refreshToken");
oAuth2LoginSuccessHandler.onAuthenticationSuccess(request, response,
createAuthentication());
assertAll(
() -> assertThat(response.getStatus()).isEqualTo(SC_OK),
() -> assertThat(response.getContentType()).isEqualTo(APPLICATION_JSON_VALUE),
() -> verify(objectMapper).writeValue(eq(response.getOutputStream()),
any(LoginSuccessResponse.class))
);
mockUserFactory.close();
}
try-with-resources
@Test
void OAuth2_로그인이_성공하면_LoginSuccessResponse_응답을_한다() throws ServletException, IOException {
try (MockedStatic<UserFactory> mockUserFactory = mockStatic(UserFactory.class)) {
mockUserFactory
.when(() -> UserFactory.of(anyString(), anyMap()))
.thenReturn(User.builder().build());
when(userRepositoryOAuth2UserHandler.apply(any())).thenReturn(User.builder().build());
when(jwtProvider.createAccessToken(any())).thenReturn("accessToken");
when(jwtProvider.createRefreshToken(any())).thenReturn("refreshToken");
oAuth2LoginSuccessHandler.onAuthenticationSuccess(request, response,
createAuthentication());
assertAll(
() -> assertThat(response.getStatus()).isEqualTo(SC_OK),
() -> assertThat(response.getContentType()).isEqualTo(APPLICATION_JSON_VALUE),
() -> verify(objectMapper).writeValue(eq(response.getOutputStream()),
any(LoginSuccessResponse.class))
);
}
}
참고
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.2
Mockito - mockito-core 5.5.0 javadoc
Latest version of org.mockito:mockito-core https://javadoc.io/doc/org.mockito/mockito-core Current version 5.5.0 https://javadoc.io/doc/org.mockito/mockito-core/5.5.0 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org.m
javadoc.io
https://www.baeldung.com/mockito-mock-static-methods
Mocking Static Methods With Mockito | Baeldung
Explore a couple of examples of how we can use Mockito to mock static methods.
www.baeldung.com
'java' 카테고리의 다른 글
이펙티브 자바 - ITEM 5 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2024.05.20 |
---|---|
Jar 파일 배포시 FileNotFoundException 문제 (0) | 2023.08.06 |
JAVA - 기본 타입(primitive type) (0) | 2023.02.08 |