Spring Boot & 테스트 코드 작성 (3) - MockMvc
이전글
지난 글에서 Mocking 도구인 Mockito 를 다뤄 보았다.
이번에는 Spring 프레임워크에서 컨트롤러 테스트 하기위한 도구인 MockMvc
에 대해 배워보자.
MockMvc
스프링에서 MVC 테스트를 하기 위한 방법을 논의하였고, spring-test
라는 모듈을 스프링 프레임워크에 더한 것이 MockMvc
이다.
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 이 종료 된다.
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!")));
}
...
테스트를 잘 통과하는 모습을 볼 수 있다.
응답 테스트
응답으로 들어온 데이터를 검증하는 단계가 필요할 수 있다.
기존 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로 테스트하기
'java' 카테고리의 다른 글
[Spring] Spring Boot & Rest API (2) - JPA, MySQL (0) | 2020.05.18 |
---|---|
[Spring] Spring Boot & Rest API (1) (0) | 2020.05.14 |
[Spring] Spring Boot & 테스트 코드 작성 (2) - Mock, Mockito (1) | 2020.05.11 |
[Spring] Spring Boot & 테스트 코드 작성 (1) - JUnit (0) | 2020.05.08 |
[Spring] VSCode & Spring Boot (0) | 2020.05.08 |