Mockito 에러 - UnnecessaryStubbingException 해결

2024. 3. 21. 19:53·SpringBoot
목차
  1.  
  2. 문제
  3. 이유
  4. 해결
  5. 참고

 

문제

사용자가 게시판에 올린 미션 인증 글을 관리자가 승인을 해주는 기능을 만들었는데,

이와 관련해서 테스트 코드를 작성하고 있었습니다.

 

그 중에 사용자가 올린 미션 인증 글의 상태가 승인 대기중인 글이 아닐 때, 이에 맞는 오류 메시지를 반환해야 했습니다.

 

    @Test
    @DisplayName("미션 인증글 승인 - 승인 대기중인 글이 아닐 때, 오류 메시지를 잘 반환하는지?")
    void acceptMission_4() {
        // given
        Team team = TeamMock.create("팀1");
        User user = UserMock.create(team, UserRole.MENTOR, passwordEncoder);
        Mission mission = MissionMock.create();
        MissionBoard missionBoard = MissionBoardMock.create(user, mission.getId(),false, RegisterStatus.REJECTED);
        ReflectionTestUtils.setField(missionBoard, "id", 1L);

        when(missionBoardRepository.findById(any())).thenReturn(Optional.of(missionBoard));
        when(missionRepository.findById(any())).thenReturn(Optional.of(mission));

        // when & then
        MissionBoardNotInProgressException exception = assertThrows(MissionBoardNotInProgressException.class, () -> adminService.acceptMission(UserRole.ADMIN, missionBoard.getId()));
        assertEquals(exception.getMessageId(), "failed.mission-board.in-progress");
    }

위와 같이 테스트 코드를 작성하고 실행했는데, 아래와 같은 오류가 발생했습니다.

 

 

 

 

이유

이유는 생각보다 간단했습니다.

오류 메시지에서 unnecessary라고 말해주는 것처럼, 테스트 코드에서 불필요한 코드가 존재하여 이에 대한 문제를 해결해주면 되는 것이였습니다.

 

mockito-core 버전이 1.x일 때 없었던 테스트코드의 엄격성을 규정하기 위해 생긴 오류로,

mockio-core 2.x 버전부터 도입되었고, 3.x 버전 부터는 엄격성이 강제되었기 때문에

불필요한 stubbing 코드를 제거해야된다고 합니다.

 

저의 경우 해당 프로젝트에 아래와 같은 버전을 사용하고 있습니다.

 

 

 

이에 대한 해결 방법은 크게 3가지가 존재했습니다.

1. Mockito-core 버전을 1.x 또는 2.x로 다운그레이드 (비추천)

2.x 에서는 엄격성 개념이 도입되었지만,

테스트에 아래와 같이 MockitoSettings를 지정해주면 엄격성을 우회해서 테스트할 수 있다고합니다.

@Test
@MockitoSettings(strictness = Strictness.WARN)
void test_1() {
	...
}

 

2. lenient() 메서드를 앞에 추가해주기

when, doReturn 등 앞에 lenient()를 추가해서 stubbing이 미사용될 수 있도록 표시해서 해결할 수 있습니다.

// lenient()를 붙여서 mocking 결과를 항상 사용하진 않음을 표시합니다.
lenient().doReturn(fixedClock.instant()).when(clock).instant();
lenient().doReturn(fixedClock.getZone()).when(clock).getZone();

 

3. 필요없는 stubbing 제거

사용할 필요가 없는 when, doReturn, doThrow 등을 제거해서 해결하는 방법입니다.

불필요한 테스트가 줄어들기 때문에 나중에 코드를 수정하는 사람이 테스트코드를 이해하는데 편해진다는 장점이 있습니다.

 

 

 

해결

저는 3번의 방법으로 해결했습니다.

 

    /**
     * 미션 인증 글 승인
     */
    @Transactional
    public void acceptMission(UserRole userRole, Long missionBoardId) {
        if (!userRole.isAdmin()) {
            throw new NotGrantedException();
        }

        MissionBoard missionBoard = missionBoardRepository.findById(missionBoardId).orElseThrow(PostNotFoundException::new);

        if (missionBoard.getRegisterStatus().equals(ACCEPTED)) {
            throw new AlreadyMissionBoardAcceptedException();
        }

        if (missionBoard.getRegisterStatus().equals(IN_PROGRESS)) {
            Team team = missionBoard.getUser().getTeam();
            Mission mission = missionRepository.findById(missionBoard.getMissionId()).orElseThrow(MissionNotFoundException::new);
            if (missionBoard.isBonusMissionSuccessful()) {
                BonusMission bonusMission = bonusMissionRepository.findAllByMissionId(mission.getId()).get(0);

                int totalScore = mission.getPoint() + bonusMission.getPoint();
                team.addScore(totalScore);
                teamRepository.save(team);
            } else {
                team.addScore(mission.getPoint());
                teamRepository.save(team);
            }
            missionBoard.changeRegisterStatus(ACCEPTED);
            missionBoardRepository.save(missionBoard);

            CompletedMission completedMission = CompletedMission.builder()
                    .team(team)
                    .mission(mission)
                    .isBonusSuccess(missionBoard.isBonusMissionSuccessful())
                    .build();
            completedMissionRepository.save(completedMission);
        } else {
            throw new MissionBoardNotInProgressException();
        }
    }

 

위의 메소드에 대한 테스트 코드를 작성하고 있었는데,

생각을 해보니 승인 대기중인 글이 아닌 상태에 대해서 오류 메시지를 검증하는 테스트 코드 였기 때문에

if (missionBoard.getRegisterStatus().equals(IN_PROGRESS)) 이 아닌 

else문으로 빠져서 throw new MissionBoardNotInProgressException(); 가 실행됩니다.

 

그러므로 if문 안의 missionRepository.findById(missionBoard.getMissionId())는 수행되지 않기때문에

테스트 코드에서 when(missionRepository.findById(any())).thenReturn(Optional.of(mission));는 불필요한 코드에 해당됩니다.

 

그러므로 테스트 코드에서 해당 when 부분을 삭제해서 해결했습니다.

    @Test
    @DisplayName("미션 인증글 승인 - 승인 대기중인 글이 아닐 때, 오류 메시지를 잘 반환하는지?")
    void acceptMission_4() {
        // given
        Team team = TeamMock.create("팀1");
        User user = UserMock.create(team, UserRole.MENTOR, passwordEncoder);
        Mission mission = MissionMock.create();
        MissionBoard missionBoard = MissionBoardMock.create(user, mission.getId(),false, RegisterStatus.REJECTED);
        ReflectionTestUtils.setField(missionBoard, "id", 1L);

        when(missionBoardRepository.findById(any())).thenReturn(Optional.of(missionBoard));

        // when & then
        MissionBoardNotInProgressException exception = assertThrows(MissionBoardNotInProgressException.class, () -> adminService.acceptMission(UserRole.ADMIN, missionBoard.getId()));
        assertEquals(exception.getMessageId(), "failed.mission-board.in-progress");
    }

 

테스트 코드가 잘 수행되는 것을 확인할 수 있었습니다.

 

 

 

 

참고

 

Mockito Strict Stubbing and The UnnecessaryStubbingException | Baeldung

Understand the reasons behind the Mockito UnnecessaryStubbingException and how to avoid it.

www.baeldung.com

 

 

Mockito 사용중 Unnecessary Stubbing Exception 해소하기

Mockito 사용중 Unnecessary Stubbing Exception 해소하기 Aug 15, 2021 Mockito 사용중 Unnecessary Stubbing Exception 해소하기 Spring Boot에서 JUnit5와 이에 포함된 Mockito Core 3.x 버전을 사용할 때 아래와 같이 UnnecessaryStubb

widian.github.io

 

 

 

Strictness in Mockito · Issue #769 · mockito/mockito

Introduction This issue explores the addition of "strict" behavior and APIs to Mockito. Traditionally, Mockito is a lenient mocking framework. For background and motivation, check out Szczepan's sh...

github.com

 

 

 

'SpringBoot' 카테고리의 다른 글

프로메테우스와 그라파나를 사용하여 모니터링 수행하기  (0) 2024.03.28
기존에 동시성 이슈 문제 해결을 위해 사용한 Redisson 대신 Redis의 script를 사용해서 성능 올리기  (0) 2024.03.24
쿠폰 발급 요청 시, 확인하는 쿠폰 정보를 Redis Cache에 담아 개선하기  (0) 2024.03.19
[Spring Boot] 채팅방에서 사용자가 업로드한 파일을 NHN Cloud의 Object Storage를 통해 관리하기  (0) 2024.02.07
Spring-Data-DynamoDB를 사용하여 SpringBoot와 AWS DynamoDB 연동하기  (0) 2024.01.28
  1.  
  2. 문제
  3. 이유
  4. 해결
  5. 참고
'SpringBoot' 카테고리의 다른 글
  • 프로메테우스와 그라파나를 사용하여 모니터링 수행하기
  • 기존에 동시성 이슈 문제 해결을 위해 사용한 Redisson 대신 Redis의 script를 사용해서 성능 올리기
  • 쿠폰 발급 요청 시, 확인하는 쿠폰 정보를 Redis Cache에 담아 개선하기
  • [Spring Boot] 채팅방에서 사용자가 업로드한 파일을 NHN Cloud의 Object Storage를 통해 관리하기
개발이조아용
개발이조아용
IT 개발에서 배운 성장의 기록을 작성합니다.
  • 개발이조아용
    계속 하다 보면?!
    개발이조아용
  • 전체
    오늘
    어제
    • 분류 전체보기 (65)
      • Tibero DB (Tmax AI Bigdata .. (7)
      • Git (2)
      • CI CD (2)
      • Redis (3)
      • SpringBoot (15)
      • SQL 문제 풀이 (8)
      • Apache Kafka (8)
        • 오류 해결 (3)
        • 개념 정리 (4)
        • 보안 (1)
      • Nginx (3)
      • SW마에스트로 (3)
      • Kubernetes (4)
      • AWS (5)
      • gRPC (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Redis 개념
    KAFKA
    redis
    DynamoDB 연동
    SpringBoot
    Git
    Kafka SASL
    leetcode
    redis script
    nginx
    Kafka 오류
    Tibero
    SASL 인증
    sql 문제
    SQL
    MSA
    소프트웨어 마에스트로
    grpc
    K8S
    Kafka 개념
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
개발이조아용
Mockito 에러 - UnnecessaryStubbingException 해결
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.