T_era

테스트 코드 어노테이션 및 메서드 정리 본문

Programing/Spring

테스트 코드 어노테이션 및 메서드 정리

블스뜸 2025. 6. 9. 15:47

Mockito 어노테이션과 메서드 검증에 대한 정리

1. Mockito 어노테이션

@Mock

  • 가짜 객체를 생성하는 어노테이션
  • 제 객체의 동작을 시뮬레이션할 수 있음
  • 든 메서드가 기본값을 반환 (null, 0, false 등)
  • 주로 외부 의존성을 가진 객체를 테스트할 때 사용
@Mock
UserRepository userRepository;  // 가짜 객체 생성

// 사용 예시
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
 

@InjectMocks

  • 생성된 가짜 객체를 주입받는 클래스에 사용
  • @Mock으로 생성된 객체들을 자동으로 주입
  • 주로 테스트 대상 클래스에 사용
@Mock
UserRepository userRepository;

@InjectMocks
UserService userService;  // userRepository가 자동으로 주입됨

@Spy

  • 실제 객체와 메서드 모킹을 모두 사용해야 할 때 사용
  • 실제 객체의 메서드를 호출하되, 필요한 경우에만 특정 메서드를 오버라이드
  • 선언과 동시에 초기화해야 함
  • 실제 객체의 대부분의 동작을 유지하면서 특정 메서드만 모킹할 때 유용
@Spy
JwtUtil jwtUtil = new JwtUtil();  // 선언과 동시에 초기화

// 사용 예시
doReturn("mocked_token").when(jwtUtil).createToken(anyLong(), anyString(), any());

 

2. 메서드 사용 검증

verify()

  • Mock 객체의 메서드 호출을 검
  • 호출 횟수, 호출 순서, 호출 인자 등을 검증 가능
verify(userRepository).findById(1L);

// 호출 횟수 검증
verify(userRepository, times(2)).findById(1L);
verify(userRepository, never()).delete(any());
verify(userRepository, atLeastOnce()).save(any());

// 호출 순서 검증
InOrder inOrder = inOrder(userRepository);
inOrder.verify(userRepository).findById(1L);
inOrder.verify(userRepository).save(any());
 
 

verifyNoMoreInteractions()

  • Mock 객체의 추가적인 메서드 호출이 없는지 검
  • 예상치 못한 메서드 호출을 방지
 
verify(userRepository).findById(1L);
verifyNoMoreInteractions(userRepository);  // 다른 메서드 호출이 없어야 함

3. given()과 when()의 차이

when()

  • Mockito의 기본 메서드
  • 전통적인 테스트 스타일에서 사용
  • 문법: when(mock.method()).thenReturn(value)
 
when(userRepository.findById(1L)).thenReturn(Optional.of(user));

given()

  • BDD(Behavior Driven Development) 스타일의 테스트를 위한 메서드
  • 더 자연스러운 문장처럼 읽힘
  • 문법: given(mock.method()).willReturn(value)
given(userRepository.findById(1L)).willReturn(Optional.of(user));

 

4. 실제 사용 예시

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;
    
    @Mock
    private PasswordEncoder passwordEncoder;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    void signup_success() {
        // given
        SignupRequest request = new SignupRequest("test@test.com", "password", "USER");
        User user = new User("test@test.com", "encodedPassword", UserRole.USER);
        
        // given
        given(userRepository.existsByEmail(anyString())).willReturn(false);
        given(passwordEncoder.encode(anyString())).willReturn("encodedPassword");
        given(userRepository.save(any(User.class))).willReturn(user);
        
        // when
        SignupResponse response = userService.signup(request);
        
        // then
        assertThat(response.getBearerToken()).isNotNull();
        
        // verify
        verify(userRepository).existsByEmail(request.getEmail());
        verify(passwordEncoder).encode(request.getPassword());
        verify(userRepository).save(any(User.class));
        verifyNoMoreInteractions(userRepository, passwordEncoder);
    }
}

 

이러한 Mockito의 기능들을 활용하면 아래와 같은 장점이 있다:

  1. 외부 의존성 없이 테스트 가능
  2. 스트 실행 속도 향상
  3. 다양한 시나리오 테스트 가능
  4. 테스트 코드의 가독성 향상