Spring Boot & 테스트 코드 작성 (3) - MockMvc

Spring Boot & 테스트 코드 작성 (3) - MockMvc

이전글

지난 글에서 Mocking 도구인 Mockito 를 다뤄 보았다.
이번에는 Spring 프레임워크에서 컨트롤러 테스트 하기위한 도구인 MockMvc 에 대해 배워보자.

MockMvc

스프링에서 MVC 테스트를 하기 위한 방법을 논의하였고, spring-test 라는 모듈을 스프링 프레임워크에 더한 것이 MockMvc 이다.

Spring Framework 3.2 RC1: Spring MVC Test Framework

MockMvc Test 예제

package com.example3.demo;

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

@SpringBootTest
@AutoConfigureMockMvc
class DemoControllerTest {

    // 아래 BeforeEach 에서 mockMvc 객체를 초기화 하는 것과 같다.
    @Autowired
    public MockMvc mockMvc;

    // 이 부분은 Autowired 한 것과 동일하다
    @BeforeEach
    public void before() {
        mockMvc = 
            MockMvcBuilders
                .standaloneSetup(DemoController.class) // 테스트 대상 Controller 를 넣어준다.
                .alwaysExpect(MockMvcResultMatchers.status().isOk()) // 특정 필수 조건을 지정
                .build();
    }


    @Test
    public void hello() throws Exception {    
        mockMvc.perform(
            MockMvcRequestBuilders
            .get("/") // 넣어준 컨트롤러의 Http Method 와 URL 을 지정
            .accept(MediaType.APPLICATION_JSON) // accept encoding 타입을 지정
        )
        .andExpect(status().isOk())
        .andExpect(content().string(equalTo("Hello World!"))); //응답 받은 데이터를 String 비교


    }
}

테스트를 수행하면 DEBUG CONSOLE 을 통해 Spring 프레임워크가 동작한 것을 알 수 있다.
또한 MockMvc 객체가 생성되어 MockServletContext 가 초기화 되고 모든 테스트가 끝난 후엔 Spring 이 종료 된다.

3_mockmvc_결과

Method 테스트

RestAPI 는 HTTP Protocol 의 Method 를 이용한다.
따라서 같은 URL 도 Method 에 따라 다르게 받아야 한다.

HTTP Method 는 대표적으로 다음이 있다.

Method Name Mapping enum value
GET RequestMethod.GET
POST RequestMethod.POST
PUT RequestMethod.PUT
DELETE RequestMethod.DELETE

DemoController.java 파일을 열어 다음과 같이 RequestMapping method 를 추가한다.

(DemoController.java)
package com.example3.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @RequestMapping(method = RequestMethod.GET, value = "/")
    public String get() {
        return "Hello World!";
    }


    @RequestMapping(method = RequestMethod.POST, value = "/")
    public String post() {
        return "Hello Post World!";
    }

}

다음 테스트 코드 또한 서로 다른 요청으로 만들어 준다.

(DemoControllerTest.java)

...

    @Disabled // 기존 테스트 무시
    @Test
    public void hello() throws Exception {    
        ...
    }

    @Test
    public void getHello() throws Exception {    
        mockMvc.perform(
            MockMvcRequestBuilders
            .get("/") // GET 요청
            .accept(MediaType.APPLICATION_JSON)
        )
        .andExpect(status().isOk())
        .andExpect(content().string(equalTo("Hello World!")));
    }

    @Test
    public void postHello() throws Exception {    
        mockMvc.perform(
            MockMvcRequestBuilders
            .post("/") // POST 요청
            .accept(MediaType.APPLICATION_JSON)
        )
        .andExpect(status().isOk())
        .andExpect(content().string(equalTo("Hello Post World!"))); 
    }
...

테스트를 잘 통과하는 모습을 볼 수 있다.

3_mockmvc_method_test

응답 테스트

응답으로 들어온 데이터를 검증하는 단계가 필요할 수 있다.
기존 Rest API 를 JSON 방식으로 변경하여 테스트를 하자.

우선 임시로 JSON string 을 그대로 반환한다.

(DemoController.java)
...
    @RequestMapping(method = RequestMethod.GET, value = "/")
    public String get() {
        // return "Hello World!";
        // JSON 문자열 반환
        return "{\"coffee\":{\"name\":\"americano\"}}";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/")
    public String post(@RequestBody String body) {
        return "Hello "+body+" World!";
    }
...

테스트 코드에서 json 과 content 타입 등을 검사한다.

(DemoControllerTest.java)
    @Test
    public void getHello() throws Exception {    
        mockMvc.perform(
            MockMvcRequestBuilders
            .get("/")
            .accept(MediaType.APPLICATION_JSON)
        )
        .andDo(MockMvcResultHandlers.print()) // 응답 데이터 출력
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON)) // Content Type을 검사
        .andExpect(jsonPath("$.coffee.name").value("americano")) // Json property, value 검사
        .andExpect(content().string("{\"coffee\":{\"name\":\"americano\"}}")); // 동일한 문자열 인지 검사
        .andExpect(content().json("{\"coffee\":{\"name\":\"americano\"}}")); // 동일한 Json 인지 검사
    }

    @Test
    public void postHello() throws Exception {    
        mockMvc.perform(
            MockMvcRequestBuilders
            .post("/") // POST 요청
            .accept(MediaType.APPLICATION_JSON)
            .content(new ObjectMapper().writeValueAsString("MOCKMVC")) //Body 삽입
        )
        .andDo(MockMvcResultHandlers.print()) // 응답 데이터 출력
        .andExpect(status().isOk())
        .andExpect(content().string(equalTo("Hello \"MOCKMVC\" World!"))); // 응답 검사
    }

이렇게 MockMvc 는 단순 Mocking 만을 제공하는 것이 아니라 Spring framework 의 Controller 를 테스트 할 수 있도록 환경을 제공한다.

엮인글

Spring Boot & 테스트 코드 작성 (1) - JUnit
Spring Boot & 테스트 코드 작성 (2) - Mock, Mockito
Spring Boot & 테스트 코드 작성 (3) - MockMvc
Spring Boot & Rest API (1)
Spring Boot & Rest API (2) - JPA, MySQL


참조

Spring Framework 3.2 RC1: Spring MVC Test Framework
MockMvc Docs
Spring MockMvc(spring-test)
스프링부트에서 컨트롤러 테스트하기
MockMvc 상세설명
Testing Java with Visual Studio Code
Junit정리 - McokMvc를 이용한 컨트롤러 테스트
Spring MockMvc로 테스트하기

+ Recent posts