300===Dev Framework/Spring Unit Test

Spring Mockito Test를 파헤쳐보자! 🧪

블로글러 2024. 11. 26. 13:31

Mockito가 뭔가요? 🤔

여러분, 영화 촬영장의 세트장을 상상해보세요! 실제 건물이 아니라 가짜 건물로 영화를 찍죠?
Mockito는 바로 이런 개념입니다!

  • 실제 객체 대신 가짜(Mock) 객체를 만들어서
  • 테스트하고 싶은 기능만 격리해서 테스트할 수 있게 해주는 프레임워크입니다

Mockito는 왜 필요한가요? 📌

  1. 독립적인 테스트 가능

    • DB 연결 없이도 Repository 테스트 가능
    • 외부 API 연동 없이도 서비스 테스트 가능
  2. 테스트 속도 향상

    • 실제 DB 연결 없이 빠른 테스트 가능
    • CI/CD 파이프라인 속도 개선
  3. 예측 가능한 테스트

    • 테스트 시나리오를 완벽하게 통제 가능
    • 랜덤한 외부 요인 제거

어떻게 사용하나요? 💻

1. Mock 객체 생성

// 방법 1: @Mock 애노테이션 사용
@Mock
private UserRepository userRepository;

// 방법 2: Mockito.mock() 메소드 사용
UserRepository userRepository = Mockito.mock(UserRepository.class);

2. Mock 동작 정의

// when-thenReturn 구문으로 동작 정의
when(metaMstRepository.findById("123"))
    .thenReturn(Optional.of(new MetaMst("123", "테스트")));

// 여러 번 호출될 때 다른 결과 반환
when(metaMstRepository.findById("123"))
    .thenReturn(Optional.of(new MetaMst("123", "첫번째")))
    .thenReturn(Optional.of(new MetaMst("123", "두번째")));

3. 검증

// verify로 메소드 호출 검증
verify(metaMstRepository).findById("123");
verify(metaMstRepository, times(2)).findById("123");

주요 기능 모음 🎯

1. 메소드 동작 설정

// 특정 값 반환
when(repository.findById(anyString())).thenReturn(Optional.empty());

// 예외 발생
when(repository.save(any())).thenThrow(new RuntimeException());

// void 메소드
doNothing().when(service).deleteUser(anyString());

2. 인자 매칭

// 정확한 값 매칭
when(repository.findById("123")).thenReturn(...);

// 임의의 값 매칭
when(repository.findById(anyString())).thenReturn(...);

// 조건부 매칭
when(repository.findById(argThat(id -> id.startsWith("user")))).thenReturn(...);

3. 검증 기능

// 호출 횟수 검증
verify(repository, times(1)).findById("123");
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findAll();

// 호출 순서 검증
InOrder inOrder = inOrder(repository, service);
inOrder.verify(repository).findById(anyString());
inOrder.verify(service).process(any());

실전 테스트 예제 📝

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void 사용자_조회_테스트() {
        // given
        String userId = "123";
        User mockUser = new User(userId, "테스트유저");
        when(userRepository.findById(userId))
            .thenReturn(Optional.of(mockUser));

        // when
        User result = userService.getUser(userId);

        // then
        assertThat(result.getId()).isEqualTo(userId);
        verify(userRepository).findById(userId);
    }
}

주의사항 ⚠️

  1. 너무 많은 Mocking은 위험

    • 실제 동작과 차이가 발생할 수 있음
    • 통합 테스트도 적절히 병행 필요
  2. Mock 객체의 한계

    • 실제 객체의 모든 동작을 완벽하게 재현 불가
    • 주요 시나리오 위주로 테스트 설계 필요

참고자료:

728x90