Spring 테스트에서 실제 호출 @SpyBean으로 확인하기
📌 서론
스프링 이벤트 리스너 클래스를 테스트하다가 잘 안 돼서 팀원과 이것저것 찾아본 결과, @SpyBean이라는 새로운 어노테이션을 알게 되었다. 이번 글에서 @SpyBean에 대해서 설명하고 다음 장에서 이 어노테이션을 사용해서 스프링 이벤트 리스너 클래스를 테스트하는 과정을 설명하겠다.
@SpyBean이란?
@SpyBean은 Spring Framework에서 제공하는 테스트 관련 어노테이션이다.
이 어노테이션은 Spring의 ApplicationContext 내에 존재하는 빈(bean)의 인스턴스를 감시(spy)하는 데 사용된다. 이는 실제 객체를 사용하지만, Mockito 프레임워크를 통해 해당 빈의 모든 메서드 호출을 감시하고, 필요한 경우 메서드의 동작을 검증하거나 변경할 수 있다.
@SpyBean의 역할과 책임
감시 기능 제공
@SpyBean은 특정 빈의 메서드 호출을 감시하고 검증하는 역할을 한다. 이를 통해 메서드가 어떻게, 몇 번 호출되는지 확인할 수 있다.
실제 동작 유지
감시 대상의 빈은 실제 실행되는 인스턴스이기 때문에, 실제 동작을 그대로 유지한다. Mockito를 사용해 필요한 경우 특정 메서드의 동작을 변경할 수 있다.
테스트 용이성
복잡한 의존성을 가진 빈의 특정 부분을 모의로 변경하여 테스트하는 데 유용하다.
사용 예제
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@SpyBean
private UserRepository userRepository;
@Test
public void whenUpdateUser_thenUserIsUpdated() {
// given
User originalUser = createNewUser();
User updatedUser = updateNewUser();
Long userId = originalUser.getUserId();
Mockito.when(userRepository.findById(userId)).thenReturn(Optional.of(originalUser));
// when
userService.updateUser(userId, updatedUser);
// then
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
Mockito.verify(userRepository).save(userCaptor.capture());
User capturedUser = userCaptor.getValue();
assertEquals("Updated Name", capturedUser.getName());
assertEquals("updated@example.com", capturedUser.getEmail());
}
private User createNewUser() {
return User.of(1L, "original name", "original@example.com");
}
private User updateNewUser() {
return User.of(1L, "updated name", "updated@example.com");
}
}
이 예제에서, UserService 클래스는 userRepository를 사용하여 사용자 정보를 조회하고 업데이트하는 로직을 포함하고 있다.
테스트 클래스에서 @Autowired를 사용하여 UserService를 주입받고, @SpyBean을 사용하여 UserRepository의 인스턴스를 감시한다.
whenUpdateUser_thenUserIsUpdated 메서드는 사용자 정보를 업데이트하는 로직을 테스트한다. 이 과정에서 userRepository의 save 메서드 호출을 Mockito를 통해 감시하고 검증하고 있다.
ArgumentCaptor를 사용하여 save 메서드에 전달된 사용자 객체를 포착하고, 그 내용이 예상대로 업데이트되었는지 확인한다.
이 예제는 @SpyBean을 사용하여 실제 빈의 일부 메서드 호출을 감시하고, Mockito를 통해 특정 동작을 검증하는 방법을 보여준다.
ArgumentCaptor는 Mockito 테스팅 프레임워크에서 제공하는 클래스로, 메서드 호출 시 전달된 인자를 포착(capture)하는 데 사용된다. 테스트 중에 어떤 인자로 특정 메서드가 호출되었는지 확인하기 위해 사용되는 유용한 도구다.
우선 ArgumentCaptor userCaptor = ArgumentCaptor.forClass(User.class);로 ArgumentCaptor를 생성한다.
그리고 verify를 사용하여 userRepository.save 메서드 호출을 검증하고, 이 때 userCaptor.capture()를 호출하여 인자를 포착한다.
그 뒤에 userCaptor.getValue()를 통해 포착된 User 객체를 가져온다.
@SpyBean의 주요 사용 사례
통합 테스트
애플리케이션의 여러 구성 요소 간 상호작용을 검증하는 데 사용된다. 예를 들어, 서비스 계층이 데이터 접근 계층과의 상호작용을 올바르게 하는지 검증할 때 유용하다.
모의 객체와의 차이점
@SpyBean은 실제 객체를 사용하며, 필요한 부분만 모의로 변경할 수 있다. 이는 @MockBean과는 대조적으로 실제 로직을 대부분 유지한다.
컴포넌트 간 상호작용 검증
서비스가 다른 서비스나 리포지토리와의 상호작용을 검증하는 데 사용된다.
부수 효과 검증
외부 시스템에 대한 부수 효과를 발생시키는 로직을 검증한다.
이벤트 처리 로직 검증
이벤트 처리 로직이 올바르게 동작하는지 검증한다.
결론
@SpyBean은 Spring Boot 애플리케이션에서 통합 테스트를 수행할 때 중요한 도구이다. 이 어노테이션은 실제 빈의 인스턴스를 사용하여 애플리케이션의 실제 동작을 유지하면서, 동시에 Mockito를 통해 필요한 메서드의 동작을 검증하거나 변경할 수 있다.
이를 통해 애플리케이션의 다양한 구성 요소 간 상호작용을 정확하게 검증하고, 복잡한 의존성을 가진 시스템의 테스트를 용이하게 할 수 있다.
이제 다음 글에서 스프링 이벤트 리스너 클래스를 테스트하면서 실제로 @SpyBean이 어떻게 사용되는지 같이 확인하자.
테스트 코드의 가독성 향상 - BDD 방법론과 @DisplayName 어노테이션 활용
'Spring > Spring 테스트코드' 카테고리의 다른 글
Mockito when().thenReturn()에서 파라미터로 eq()와 직접 변수 사용의 차이점 이해하기 (0) | 2024.01.11 |
---|---|
테스트 격리성의 중요성과 모의 객체(Mock Object)를 활용한 전략 (3) | 2024.01.01 |
스프링 테스트 코드: @MockBean과 @Mock의 차이 (+ @InjectMocks) (1) | 2023.12.31 |
테스트 코드의 가독성 향상 - BDD 방법론과 @DisplayName 어노테이션 활용 (2) | 2023.12.26 |
테스트 전략에서 단위 테스트와 통합 테스트의 차이점과 의존성 관리 (1) | 2023.12.25 |