org.mockito.exceptions.misusing.UnnecessaryStubbingException 해결
2023. 11. 7. 10:42ㆍProject 해축갤/테스트 코드
728x90
// PostService의 게시글 수정(updatePost) 정상 케이스 테스트 코드
@Test
public void updatePost_ShouldChangePostDetails_WhenUpdateInfoIsValid() throws Exception {
// given - 상황 만들기
Long postId = 1L;
PostUpdateDTO postUpdateDTO = PostUpdateDTO.builder()
.title("Updated Title")
.content("Updated Content")
.build();
Post existingPost = Post.builder()
.id(postId)
.title("Title")
.content("Content")
.build();
when(postRepository.findById(postId))
.thenReturn(Optional.of(existingPost));
// when - 동작
existingPost.updateFieldsFromUpdateDto(postUpdateDTO);
// then - 검증
assertEquals("Updated Title", existingPost.getTitle());
assertEquals("Updated Content", existingPost.getContent());
}
//...
// PostService의 게시글 수정
@Transactional
public void updatePost(Long postId, PostUpdateDTO postUpdateDTO) {
// DB 에 해당 게시물 존재하는 지 확인
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(POST_NOT_FOUND_BY_ID, postId));
// post 의 field 들 업데이트
post.updateFieldsFromUpdateDto(postUpdateDTO);
// DB 에 save
postRepository.save(post);
}
위와 같이 updatePost의 테스트 코드를 작성했다가 다음과 같은 에러를 맞이했다.
설명을 읽어보면, 불필요한 Stubbing 을 해서 에러가 났다는 건데
이게 과연 Exception 이 날 정도의 건가 싶어서 UnnecessaryStubbingException.java의 주석을 확인,
그 이유를 알았습니다.
주석을 통한 이해
UnnecessaryStubbingException은 사용되지 않은 스텁(stub)이 있다는 것을 나타내는데,
이는 Mockito 테스트에서 stub 설정이 실제로 테스트 실행 중에 사용되지 않았음을 의미합니다.
Mockito는 불필요한 코드를 제거하고 코드베이스를 깨끗하게 유지할 것을 권장합니다.
만약 사용되지 않은 stub이 실제로는 필요하지 않은 것이 아니라면 즉, false negative 인 경우
(사용되지 않는 Stub 설정이 필요한 거 같이 매우매우 드문 경우라는 뜻으로 이해하면 됩니다.)
다음과 같은 방법으로 검증에서 제외할 수 있습니다:
1. 특정 스텁을 '관대하게(lenient)' 설정하기: Mockito.lenient()
2. 특정 목(mock)을 '관대하게' 설정하기: org.mockito.MockSettings.lenient()
3. Mockito JUnit 지원(org.mockito.junit.MockitoJUnit) 또는
Mockito 세션(MockitoSession)을 사용하여 테스트 클래스 또는 테스트 메소드의 모든 목을 '관대하게' 설정하기
사용되지 않은 스텁은 테스트 실행 도중에 실제로 호출되지 않은 스텁 메소드입니다.
예를 들면 다음과 같습니다:
// 코드 실행 중: ... String result = translator.translate("one"); ... // 테스트: ... when(translator.translate("one")).thenReturn("jeden"); // <- 코드 실행 중에 실현된 stub when(translator.translate("two")).thenReturn("dwa"); // <- 실현되지 않은 stub ...
위 예시에서 "one"을 번역하는 스텁은 테스트 실행 중에 실제로 사용되지만,
"two"를 번역하는 스텁은 사용되지 않습니다.
이런 경우, 사용되지 않는 스텁은 개발자의 실수, 복사-붙여 넣기의 결과, 또는 테스트/코드를
제대로 이해하지 못한 결과일 수 있습니다.
어떤 경우든, 개발자는 필요하지 않은 테스트 코드를 가지게 됩니다.
코드베이스를 깨끗하고 유지보수 가능하게 유지하기 위해서는
이런 불필요한 코드를 제거해야 합니다. 그렇지 않으면 테스트를 읽고 이해하기 어려워집니다.
Mockito JUnit Runner는 테스트 메소드 중
어느 하나라도 스텁을 사용하지 않을 때 UnnecessaryStubbingException을 발생시킵니다.
정리하자면, 저처럼 미사용한 Stub 설정을 단 1 개라도 놔둔다면 에러가 터진다는 얘기입니다!
해결 방법
- 미사용하는 Stub 설정을 다 없앤다.
- 미사용 하는 Stub 설정들을 실제로 이용한다.
저의 경우 2번에 해당합니다.
PostService 내부에서 postRepository의 메서드를 사용하고 있고,
저는 유닛테스트 코드를 만드는 중이라 stub 설정을 해야만 하기 때문이죠.
그래서 바꾼 코드는 다음과 같습니다!
@Test
public void updatePost_ShouldChangePostDetails_WhenUpdateInfoIsValid() throws Exception {
// given - 상황 만들기
Long postId = 1L;
PostUpdateDTO postUpdateDTO = PostUpdateDTO.builder()
.title("Updated Title")
.content("Updated Content")
.build();
Post existingPost = Post.builder()
.id(postId)
.title("Title")
.content("Content")
.build();
when(postRepository.findById(postId))
.thenReturn(Optional.of(existingPost));
// when - 동작
postService.updatePost(postId, postUpdateDTO);
// then - 검증
assertEquals("Updated Title", existingPost.getTitle());
assertEquals("Updated Content", existingPost.getContent());
}
728x90
'Project 해축갤 > 테스트 코드' 카테고리의 다른 글
테스트 띠띠ㅣ디ㅣ디ㅣ딛ㄹ딸깍? postman 으로 '띡띡딸깍' 하기 (1) | 2023.11.30 |
---|---|
Hibernate의 "Detached Entity Passed to Persist" 오류 이해와 해결 (0) | 2023.11.08 |
테스트를 더 빨리 끝내보기 (feat. 자료구조, singletonList) (0) | 2023.11.02 |
테스트 코드 작성 시 유의할 점 (Mockito doNothing) (1) | 2023.11.02 |
postman 띡띡딸깍 귀찮아서 테스트 코드 짭니다 (0) | 2023.10.31 |