Spring TDD(MockMVC)

이번 시간에는 Spring TDD MockMVC 통신에 대해서 알아보도록 하겠습니다.

1. MockMVC란?

MockMvc에 들어가기 앞서, TDD에 알아보도록 하겠습니다.

테스트 주도 개발(TDD)은 코드를 작성하기 전에 테스트 코드를 작성하는것을 말하는데 TDD의 단계는 크게 3개로 볼 수 있습니다.

  1. 테스트 작성: 구현할 기능에 대한 테스트를 작성합니다.
  2. 코드 작성: 테스트를 통과하도록 최소한의 코드를 작성합니다.
  3. 리팩토링: 코드를 정리하고 개선합니다.

MockMVC는 무엇일까요?
MockMVC는 Spring MVC 애플리케이션을 테스트할 때 사용하는 도구입니다. 이를 통해 실제 웹 서버를 실행하지 않고도 Controller 계층을 테스트할 수 있습니다. 직접 런타임시점까지 코드를 컴파일하지 않아도 직접 가상 API를 요청해볼 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.demo;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
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.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest(HelloController.class)
public class HelloControllerTest {

@Autowired
private MockMvc mockMvc;

@Test
public void testGetRequest() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("Hello, World!"));
}
}

MockMVC에 대한 간단한 예제인데요, 위 테스트 클래스는 @WebMvcTest를 사용하여 Spring MVC 애플리케이션의 특정 컨트롤러를 테스트합니다. MockMVC를 통해 PATH GET 요청을 보내고, 응답 상태가 200 OK인지와 응답 내용이 맞는지 판단합니다.

추가로 POST 방식에서 JSON형식으로 오는 값들은 어떻게 처리할까요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Test
public void testPostRequest() throws Exception {
String json = "{\"name\":\"gwan\"}";

mockMvc.perform(post("/createUser")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isCreated()) // 201 Created
.andExpect(jsonPath("$.name").value("gwan"));
}
``

$.name 같은 경우는 해당되는 json 이라는 키값이 존재하는지 확인하여 그 값을 andExpect할 수 있습니다.

이번에는 @Pathvariable@RequestParam으로 들어오는값들은 어떻게 처리 할 수 있을까요?


```java
@Test
public void testPathVariable() throws Exception {
mockMvc.perform(get("/user/{id}", 1))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.name").value("gwan"));
}
@Test
public void testRequestParam() throws Exception {
mockMvc.perform(get("/search")
.param("query", "gwan"))
.andExpect(status().isOk())
.andExpect(content().string("Search results for: gwan"));
}

그 외에는 Header값이 어떻게 들어오는지도 파악할 수 있습니다.

1
2
3
4
5
6
@Test
public void testResponseHeader() throws Exception {
mockMvc.perform(get("/download"))
.andExpect(status().isOk())
.andExpect(header().string("Content-Type", "application/octet-stream"));
}

perform 메서드는 HTTP 요청을 시뮬레이션하고, andExpect 메서드는 그에 따른 응답을 검증할 수 있게 됩니다. 보통 given-when-then 패턴을 많이 사용하는것으로 알고 있고 저도 실제로 대외 프로젝트를 진행하면서 given-when-then 패턴을 사용하여 해당 TDD 단위 테스트를 진행한 경험을 가지고 있습니다.

그 만큼 단위테스트는 중요한 부분이고 추후 실무에서 개발기간을 단축시킬 수 있는 큰 요소라고 생각을 합니다.