본문 바로가기

Backend/SpringBoot

SpringBoot의 MockMvc를 사용하여 GET, POST 응답 테스트하기

안녕하세요! 이번 포스팅에서는 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 요청도 보낼 수 있으니 다방면으로 유용하게 사용할 수 있을 것 같습니다.

혹시 위 글에서 잘못된 내용이나 보충하고 싶은 내용을 알려주시면 감사하겠습니다 :)