컨트롤러 단위 테스트를 작성할 때는 @WebMvcTest 등으로 웹 계층의 빈만 주입받는다.
이 때 컨트롤러가 의존하는 객체(서비스 등)는 @MockBean 등으로 만들어준다.
mock 객체 stubbing을 해야한다
나는 이제까지 mock 객체의 메서드가 호출된다면 stubbing을 해줘야 한다고 생각했다.
예를 들어 컨트롤러 단위 테스트 시에 서비스는 stubbing을 통해 정상작동하는 것을 보장해야 컨트롤러에 대해서만 테스트 할 수 있다고 생각했다.
@WebMvcTest(MessageController.class)
class MessageControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MessageService messageService;
@Test
void testGetMessage() throws Exception {
// Given: 서비스 메서드가 특정 값을 반환하도록 Stubbing
Long messageId = 1L;
String expectedMessage = "Hello, this is a mock message!";
when(messageService.getMessageById(messageId)).thenReturn(expectedMessage);
// When: 컨트롤러로 요청을 보냄
mockMvc.perform(get("/api/messages/{id}", messageId)
.contentType(MediaType.APPLICATION_JSON))
// Then: 응답 검증
.andExpect(status().isOk())
.andExpect(content().string(expectedMessage));
// Verify: 서비스 메서드가 호출되었는지 확인
verify(messageService).getMessageById(messageId);
}
}
위의 예시처럼 mock 객체 MessageService는 when ~ thenReturn
에 의해 stubbing되어 동작한다.
MessageController가 실제 빈으로써 동작하고 해당 빈에 대해 테스트 할 수 있다.
불필요하다면 mock 객체 stubbing을 굳이 안해도 된다
최근 테스트코드 관련 회의하며 유지보수팀 분께서 컨트롤러 단위 테스트에 서비스는 @MockBean
으로 사용하시면서 stubbing은 안하고 기본값 (null 등)을 반환하도록 테스트하는 것을 보게 되었다. 관련해서 질문드렸더니
컨트롤러 계층은 서비스, 리포지토리를 몰라야 한다. 컨트롤러의 역할은 요청을 받아서 서비스에게 넘겨주는 역할이다. 따라서 컨트롤러는 서비스 응답 값에 대해 알 필요가 없다. 따라서 컨트롤러 단위 테스트에서는 굳이 stubbing이 필요하지 않다고 생각한다.
이렇게 말씀해주셨다. 컨트롤러의 책임은 요청을 받아서 서비스에게 넘겨주는 것이다. 비즈니스 로직은 서비스가 수행하고 수행 결과도 서비스가 만든다. 따라서 컨트롤러 단위 테스트 시에는 서비스 응답값이 필요한 상황이 아니라면 굳이 stubbing 할 필요가 없다.
@WebMvcTest(MessageController.class)
class MessageControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MessageService messageService;
@Test
void testGetMessageWithoutStubbing() throws Exception {
// Given: Stubbing 없이 테스트 진행
Long messageId = 1L;
// When: 컨트롤러로 요청을 보냄
mockMvc.perform(get("/api/messages/{id}", messageId)
.contentType(MediaType.APPLICATION_JSON))
// Then: 응답 검증
.andExpect(status().isOk());
// Verify: 서비스 메서드가 호출되었는지 확인
verify(messageService).getMessageById(messageId);
}
}
위와 같이 서비스의 책임인 요청을 잘 받고, 서비스에게 넘겨주었는지 (verify
로 확인) 를 테스트하면 된다.
관련해서 개발자 커뮤니티에도 질문했었는데 답변을 너무 잘해주셔서 간단하게 정리하고 글을 마무리하겠다.
- stubbing을 하던 말던 컨트롤러 동작은 똑같다
- 오히려 service, repository가 변경되면 서비스 단위테스트도 영향을 받을 수 있어 번거롭다
- 대부분 REST Controller는 url mapping, parameter 전달만 해주니까 컨트롤러 메서드가 호출되어 값이 잘 넘어오는지만 검증해도 충분하다.
- 응답값에 이상이 있더라도 컨트롤러를 고칠 것은 아니다. 컨트롤러는 값을 전달했을 뿐이고 응답은 비즈니스 로직에서 처리한다.
- 컨트롤러는 굳이 단위테스트를 작성하지 않고 통합 테스트로 퉁치는? 경우가 많다.
'테스트' 카테고리의 다른 글
테스트에서 @CreatedDate 정렬 문제 해결하기 (0) | 2025.02.11 |
---|---|
@ParameterizedTest를 사용해보자 (0) | 2024.10.31 |
테스트 더미데이터 삽입 방법 (2) | 2024.10.21 |
테스트 환경 (@SpringBootTest와 @WebMvcTest) (1) | 2024.09.08 |
댓글