스프링 프레임워크에는 MockMvc라는 Spring MVC Test 프레임워크가 존재합니다.
서버를 구동하고 있지 않아도 Spring MVC 요청을 처리하는 모듈에서 모의 서블릿을 전달하고 디스패처 서블릿을 구동합니다.
즉, MockMvc는 모의 요청, 응답을 이용해 테스트하고자 하는 시나리오를 가볍게 테스트할 수 있는 프레임워크입니다.
오늘은 MockMvc를 간단하게 알아보고, Controller를 테스트 하는 코드를 작성하고자 합니다.
MockMvc 설정
MockMvc를 이용하여 요청을 보내기 위해 몇가지 클래스를 먼저 알아둬야 합니다.
MockMvcBuilders.*
MockMvcRequestBuilders.*
MockMvcResultMatchers.*
MockMvcResultHandlers.*
위 클래스들이 지원하는 정적 메서드를 이용해 MockMvc를 설정할 수 있습니다.
@SpringBootTest
class HelloControllerTest {
private MockMvc mockMvc;
@Autowired
private HelloController helloController;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(helloController)
.build();
}
}
위와 같이 컨트롤러를 직접 standaloneSetup
키워드에 넣어두고 테스트하는 방식은 매 단위 테스트마다 주입하고자 하는 컨트롤러를 달리하고 따로 주입해야 하는 단점이 있어 아래와 같은 방법을 더 선호합니다. (다만 빠르게 해당 컨트롤러에 대한 피드백을 받고 싶을 때에는 위와 같이 설정해도 좋습니다.)
@WebMvcTest(HelloController.class)
class HelloControllerTest {
@Autowired
MockMvc mockMvc;
}
해당 방식을 통해 컨트롤러를 컨텍스트에 캐싱해두고 테스트를 수행합니다.
다만 @WebMvcTest 애노테이션은 WebMvcTestContextBootstrapper를 사용하기 때문에 모든 의존성을 가져오지 않아 의존성이 필요한 내용에 대해서는 @MockBean애노테이션을 이용하여 모의 객체를 주입하는 과정이 필요합니다.
@WebMvcTest(HelloController.class)
class HelloControllerTest {
@Autowired
MockMvc mockMvc;
@MockBean // 모킹된 객체는 당연히 구현된 기능을 수행 못합니다.
HelloDao helloDao;
또한 @WebMvcTest를 달아둔 추상클래스를 상속하여 Controller Test를 동일한 스프링 컨테이너에서 테스트 하여 테스트 성능을 최적화 할 수도 있습니다.
// 동일한 설정이기 때문에 스프링 컨테이너를 한 번만올려 이를 상속한 클래스들을 한 컨테이너 내에서 실행합니다.
@WebMvcTest({
HelloController.class,
WelcomeControllerTest.class
})
public abstract class ControllerTest {
@Autowired
protected MockMvc mockMvc;
@MockBean
protected HelloDao helloDao;
}
요청 생성
위 클래스 중 MockMvcRequestBuilders
를 이용하여 요청을 생성할 수 있습니다.
@Test
void hello() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/hello")).
...;
}
위 코드를 이용하여 /hello url로 요청을 보낼 수 있습니다.
동일한 방식으로 다른 http 메서드에 대한 요청도 생성할 수 있습니다.
@Test
void hello() throws Exception {
mockMvc.perform(post("/hello")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString))
...;
}
추가적으로 원하는 헤더값을 보낼 수도 있고, 원하는 content를 String이나 byte 형태로 보낼 수도 있습니다.
Spring boot는 ObjectMapper를 의존성으로 올려두고 있기 때문에 부모 Controller에 해당 클래스를 의존성 주입받아 사용할 수 있습니다.
결과 확인
요청이 생성되면 당연히 원하는 결과를 반환하는지 확인해야 하는데요.
이 내용은 MockMvcResultMatchers
클래스로 확인할 수 있습니다.
@Test
void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("HelloWorld!"));
}
어떤 상태코드를 반환하고, 어떤 내용을 반환하는지 확인할 수 있습니다.
추가적으로 MockMvcResultHandlers.print()
를 통해 위 파이프라인이 어떤 Http 요청을 생성했고, 어떤 Http 응답을 받았는지 확인할 수 있습니다.
@Test
void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("HelloWorld!"))
.andDo(print());
}
마무리
여러가지 컨트롤러 테스트 방법이 있고, MockMvc는 그 중 하나입니다. 어떤 방식을 사용할지는 상황에 따라 차이가 있으니 잘 알아보고 사용하면 좋을 듯 합니다.
또한 spring-framework 깃헙에 많은 테스트 예제들이 있고 레퍼런스에도 설명이 상세히 나와있으니 한 번 정독하며 직접 코드를 작성해보는 것도 좋을 것 같습니다.
'우아한테크코스 4기 > 레벨2' 카테고리의 다른 글
[SQL] 페이징 구현하기 (2) | 2022.05.07 |
---|---|
[Spring] Transaction 추상화, 동기화 (0) | 2022.04.27 |
[Spring] 컨트롤러 테스트 시 한글 깨짐 문제 해결 (0) | 2022.04.24 |
[Spring] NamedParameterJdbcTemplate 사용하기 (4) | 2022.04.21 |
[Spring] Spring Boot에서 트랜잭션 사용하기 (1) | 2022.04.20 |