상황
MenuRankingServiceTest 작성 중 @BeforeEach에 opsForZSet() 스텁을 등록했는데, 아래 에러가 발생했다.
Unnecessary stubbings detected.
Following stubbings are unnecessary:
1. -> at MenuRankingServiceTest.setUp(MenuRankingServiceTest.java:49)
원인
원인은 Redis에 데이터가 없어 즉시 반환하는 테스트에서 opsForZSet()이 한 번도 호출되지 않았기 때문이다.
// getPopularMenus() 내부
if (existingKeys.isEmpty()) {
return Collections.emptyList(); // opsForZSet() 호출 전에 반환
}
@ExtendWith(MockitoExtension.class)의 strict stubbing은 등록된 스텁이 한 번도 사용되지 않으면 예외를 던진다.
해결 방법 비교
두 가지 선택지를 검토했다.
첫 번째는 각 테스트에 직접 스텁을 추가하는 방법이다. strict stubbing이 완전히 유지되고 각 테스트가 자기완결적이라는 장점이 있다. 그러나 데이터 없음 케이스 외 모든 테스트에 동일한 한 줄을 반복 추가해야 한다.
두 번째는 @BeforeEach에서 lenient()를 사용하는 방법이다. @BeforeEach 한 줄로 끝나고 코드 중복이 없다. lenient()는 해당 스텁 하나에만 적용되므로, 나머지 스텁에 대한 strict stubbing 감지는 그대로 유지된다.
| 각 테스트에 직접 추가 | @BeforeEach에서 lenient() 사용 | |
| 코드량 | 예외 테스트 1개를 제외한 모든 테스트에 반복 추가 | @BeforeEach 1줄로 끝남 |
| 명시성 | 각 테스트가 자기완결적 | 암묵적 |
| strict stubbing 유지* | 완전히 유지 | 해당 스텁에 한해 완화 |
*자기완결적 : 테스트 하나만 봐도 이 테스트가 무엇을 준비하고 무엇을 검증하는지 전부 파악할 수 있음
*strict stubbing : 등록해뒀지만 실제로 한 번도 안 쓴 stubbing이 있으면 에러를 던지는 기능
나의 선택
@BeforeEach에서 lenient()로 선언하는 방법을 선택했다.
@BeforeEach
void setUp() {
lenient().when(redisTemplate.opsForZSet()).thenReturn(zSetOps);
}
opsForZSet()은 데이터 없음 케이스를 제외한 모든 테스트에서 사용된다. 12개 테스트에 동일한 한 줄을 반복 추가하는 것은 잡음만 늘릴 뿐이다.
lenient()는 strict stubbing을 전면 해제하지 않는다. 해당 스텁 하나에만 적용되므로, 나머지 스텁에 대한 UnnecessaryStubbingException 감지는 그대로 유지된다. PointServiceTest의 동시성 테스트에서도 같은 이유로 lenient()를 사용하고 있어 프로젝트 내 패턴이 일관된다.
'Projects > [Spring] Coffee Shop Project' 카테고리의 다른 글
| [트러블슈팅] : Redis 캐시 역직렬화 실패 - 기본 생성자가 없는 경우 (0) | 2026.04.05 |
|---|---|
| [트러블슈팅] Spring Boot 4.x 업그레이드 시 Jackson 패키지 변경 주의하기 (0) | 2026.04.05 |
| [트러블슈팅] soft delete된 메뉴의 인기 랭킹 처리, 어떻게 할까? (0) | 2026.04.05 |
| [트러블슈팅] : Kafka 역직렬화 오류 - trusted packages 불일치 (0) | 2026.04.05 |
| [트러블슈팅] Spring Boot 4 마이그레이션 후 contextLoads() 테스트 실패 해결기 (0) | 2026.04.04 |