안녕하세요! 이번 포스팅에서는 SpringBoot 프레임워크에서 제공해주는 MockMvc를 만들고 테스트하는 방법을 알아보도록 하겠습니다.
전체 코드는 Github에서 확인이 가능합니다. ✍️
📚 개념 정리
1. MockMvc란?
실제 객체와 비슷하지만 테스트에 필요한 기능만 가지는 가짜 객체를 만들어서 애플리케이션 서버에 배포하지 않고도 스프링 MVC 동작을 재현할 수 있는 클래스를 의미합니다.
2. 사용방법
Junit4를 사용하기 위해 의존성에 spring-boot-starter-test를 추가해줍니다.
build.gradle
testCompile("org.springframework.boot:spring-boot-starter-test")
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
👆 GET 방식으로 사용하기
1. Controller 추가
가장 먼저 컨트롤러를 추가해줍니다.
BlogController.java
@RestController
public class BlogController {
@GetMapping("/blog")
public String blogGet(@RequestParam String name, @RequestParam String id){
return name + "의 블로그입니다. " + id;
}
}
@RequestParam을 사용해서 name과 id를 받고, 그대로 리턴해주는 컨트롤러를 작성했습니다.
2. Test 추가
방금 작성한 컨트롤러에 대한 테스트를 추가해줍니다.
intelliJ의 경우에는 컨트롤러 이름 끝에서 Alt + Enter를 누르면 간편하게 추가할 수 있습니다. 저는 Junit4를 사용하기 때문에 Testing library를 Junit4로 지정해주었습니다.
BlogControllerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest(BlogController.class)
public class BlogControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void 테스트_GET() throws Exception {
MultiValueMap<String, String> info = new LinkedMultiValueMap<>();
info.add("name", "칩");
info.add("id", "chip");
mockMvc.perform(get("/blog") // 1, 2
.params(info)) // 3
.andExpect(status().isOk()) // 4
.andExpect(content().string("칩의 블로그입니다. chip"))
.andDo(print()); // 5
}
위와 같이 코드를 작성해줍니다.
🐬 mockMvc의 메소드
1) perform()
- 요청을 전송하는 역할을 합니다. 결과로 ResultActions 객체를 받으며, ResultActions 객체는 리턴 값을 검증하고 확인할 수 있는 andExcpect() 메소드를 제공해줍니다.
2) get("/mock/blog")
- HTTP 메소드를 결정할 수 있습니다. ( get(), post(), put(), delete() )
- 인자로는 경로를 보내줍니다.
3) params(info)
- 키=값의 파라미터를 전달할 수 있습니다.
- 여러 개일 때는 params()를, 하나일 때에는 param()을 사용합니다.
4) andExpect()
- 응답을 검증하는 역할을 합니다.
- 상태 코드 ( status() )
- 메소드 이름 : 상태코드
- isOk() : 200
- isNotFound() : 404
- isMethodNotAllowed() : 405
- isInternalServerError() : 500
- is(int status) : status 상태 코드
- 뷰 ( view() )
- 리턴하는 뷰 이름을 검증합니다.
- ex. view().name("blog") : 리턴하는 뷰 이름이 blog인가?
- 리다이렉트 ( redirect() )
- 리다이렉트 응답을 검증합니다.
- ex. redirectUrl("/blog") : '/blog'로 리다이렉트 되었는가?
- 모델 정보 ( model() )
- 컨트롤러에서 저장한 모델들의 정보 검증
- 응답 정보 검증 ( content() )
- 응답에 대한 정보를 검증해줍니다.
5) andDo(print())
- 요청/응답 전체 메세지를 확인할 수 있습니다.
3. 결과 확인
테스트를 실행하면 성공한 화면과 Request / Response 전체 메세지를 확인할 수 있습니다.
📩 POST 방식으로 사용하는 방법
이번에는 POST 방식으로 요청을 보내는 경우, 테스트를 하는 방법에 대해 알아보도록 하겠습니다.
1. VO 추가
Info.java
public class Info {
private String name;
private String id;
public Info(String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
값을 받을 VO를 만들어줍니다.
2. Controller 추가
BlogController.java
@RestController
@RequestMapping("/mock")
public class BlogController {
// ...
@PostMapping("/blog")
public String blogPost(@RequestBody Info info){
return info.getName() + "의 블로그입니다. " + info.getId();
}
}
POST로 받는 컨트롤러 메소드를 추가해줍니다.
JSON으로 값을 보낼 것이기 때문에, @RequestBody를 이용해서 객체를 받아준 후에 값을 리턴해줍니다.
3. Test 추가
BlogControllerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest(BlogController.class)
public class BlogControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
// ...
@Test
public void 테스트_POST() throws Exception {
String content = objectMapper.writeValueAsString(new Info("데일", "dale"));
mockMvc.perform(post("/blog")
.content(content)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string("데일의 블로그입니다. dale"))
.andDo(print());
}
}
이번에도 위와 같이 코드를 작성해줍니다. 각 메소드가 무슨 역할을 하는지는 아까 다뤘기 때문에 다시 다루지 않았습니다.
4. 결과 확인
이번에도 정상적으로 테스트를 통과하는 것을 확인할 수 있습니다!
만약 위 사진처럼 한글이 깨져서 테스트가 실패하는 케이스가 생기면, 아래 코드를 추가해주세요!
BlogControllerTest.java
public class BlogControllerTest {
// ...
@Autowired
private WebApplicationContext ctx;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(ctx)
.addFilters(new CharacterEncodingFilter("UTF-8", true)) // 한글 깨짐 처리
.build();
}
// ...
}
@Before 어노테이션을 사용해서 테스트를 실행하기 전에 mockMvc에 UTF-8 인코딩을 추가해주면 한글이 깨지지 않습니다.
✨ 정리
이런 식으로 간단하게 mocking을 해서 테스트를 할 수 있습니다. GET, POST 요청뿐만 아니라 DELETE, PUT 요청도 보낼 수 있으니 다방면으로 유용하게 사용할 수 있을 것 같습니다.
혹시 위 글에서 잘못된 내용이나 보충하고 싶은 내용을 알려주시면 감사하겠습니다 :)
'Backend > SpringBoot' 카테고리의 다른 글
SpringBoot의 Querydsl을 이용하여 동적쿼리(Dynamic SQL) 작성하기 (1) | 2020.02.26 |
---|---|
SpringBoot의 ControllerAdvice를 이용하여 JSON 형태로 예외처리하기 (0) | 2020.02.18 |
SpringBoot의 @IdClass를 사용해서 복합 Primary Key 적용하기 (0) | 2020.01.22 |
SpringBoot로 캐싱(Caching)하기 (0) | 2020.01.12 |
SpringBoot로 JSON 응답 보내는 방법 (GSON JsonObject, @ResponseBody, @RestController) (0) | 2019.12.26 |