SpringBoot에서 MockMvc을 활용한 컨트롤러, HTTP 요청 테스트 방법

MockMvc 소개

MockMvc:

MockMvc는 Spring Framework의 일부로, 웹 어플리케이션의 컨트롤러를 테스트하는 데 사용됩니다. 이를 통해 HTTP 요청을 시뮬레이션하고 컨트롤러의 동작을 테스트할 수 있습니다. 

  • Spring 환경을 통합한 테스트
  • Spring 컨텍스트와 통합한 테스트 (Spring Bean을 주입하여 테스트 가능)
  • HTTP 요청 및 응답 시뮬레이션

 

Spring Boot 프로젝트 설정

MockMvc와 JUnit을 사용하기 위해선 아래와 같은 의존성을 추가해야 합니다.

testImplementation 'org.springframework.boot:spring-boot-starter-test'

 

 

MockMvc를 사용한 컨트롤러 테스트

MockMvc를 구성하여 API 엔드포인트를 테스트하는 예제 코드입니다. 

@SpringBootTest
@AutoConfigureMockMvc
class ApiControllerTest {

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    protected ObjectMapper objectMapper;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void mockMvcSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
                .build();
    }

    @DisplayName("MockMvc 테스트")
    @Test
    public void firstTest() throws Exception {
    
        // given
        final String url = "/api/test";
        final RequestObject requestObject = new RequestObject("Kim", 28);
        final String requestBody = objectMapper.writeValueAsString(requestObject);

        // when
        // HTTP 요청 테스트
        ResultActions result = mockMvc.perform(post(url)
                .contentType(MediaType.APPLICATION_JSON)
                .content(requestBody));

        // then
        result.andExpect(status().isOk());
    }
💁‍♀️given, when, then 구조: 테스트의 일반적인 구조

`given, when, then`은 테스트의 일반적인 구조를 나타내는 방법론으로, 테스트 케이스를 구성하고 이해하기쉽게 만드는데 도움이 됩니다.

Given (주어진 상황):
이 단계에서는 테스트 시작 전에 주어진 초기 상황을 설정합니다. 데이터를 준비하거나 시스템 상태를 설정합니다. 이것은 테스트 시작 시의 "시작 지점"입니다.

When (만일):
이 단계에서는 주어진 상황에서 어떤 동작을 수행할 것인지를 정의합니다. 주로 특정한 동작 또는 메서드 호출을 포함하며, 이것이 실제로 테스트하려는 시나리오의 시작 부분입니다.

Then (그러면):
이 단계에서는 주어진 상황과 수행한 동작에 대한 결과를 검증합니다. 예상된 결과나 상태를 확인하고, 테스트가 성공했는지 여부를 판단합니다. "그러면 이것이 발생해야 한다" 또는 "그러면 이 결과가 나와야 한다"와 같은 명세가 포함됩니다.

이러한 구조를 사용하면 테스트 케이스를 더욱 구조적이고 읽기 쉽게 만들 수 있습니다. 각각의 단계는 특정 역할을 수행하며 테스트 케이스의 명확한 의도를 전달하는데 도움이 됩니다. 또한 실패한 경우 어떤 부분에서 문제가 발생했는지 더 쉽게 식별할 수 있습니다.

 

ResultActions와 MvcResult의 차이

ResultActions:

MockMvc를 사용하여 HTTP 요청을 보낸 후에 `ResultActions` 객체를 반환합니다. 우리는 위 예제 코드에서 ResultActions 객체를 사용하여 `result.andExpect(status().isOk())`를 통해 HTTP 응답 상태 코드를 검증했습니다. 응답 상태 코드만이 아니라 응답의 내용을 추출하고 검사하고 싶다면 MvcResult 객체를 사용하면 됩니다.

 

MvcResult:

MvcResult는 `ResultActions`를 통해 수행한 HTTP 요청에 대한 상세한정보를 담고 있는 객체입니다.
`ResultActions.andReturn()` 메서드를 사용하여 `MvcResult` 객체를 가져올 수 있고, `MvcResult`를 통해 HTTP 요청과 응답의 상세 내용(요청 본문, 응답 헤더, 본문, 모델 객체 등)을 확인할 수 있습니다.

 

즉 `ResultActions`는 HTTP 응답을 검증하고 확인하는 데 사용되는 메서드를 제공하며, 이를 통해 `MvcResult` 객체를 얻을 수 있습니다. `MvcResult`는 실제로 HTTP 요청과 응답의 내용을 검사하고 추출하는 데 사용됩니다.

 

MvcResult result = mockMvc.perform(post(url)
        .contentType(MediaType.APPLICATION_JSON)
        .content(requestBody))
        .andExpect(status().isOk())
        .andReturn();

String responseContent = result.getResponse().getContentAsString();