공부하는 스누피

[JUnit5] MockMvc로 Spring Boot 통합 테스트하기 본문

Web/Spring

[JUnit5] MockMvc로 Spring Boot 통합 테스트하기

커피맛스누피 2021. 9. 16. 20:10

API 통합 테스트

JUnit에서 제공하는 mockMvc는 api 호출을 통해 테스트를 수행합니다.

예상되는 응답을 설정할 수 있고, 실제 응답이 예상과 다를 경우 assert를 던져 테스트가 실패하도록 합니다.

 

Test Context 설정

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringApplication.class, properties = {
    ".../application-test.yaml",
    ".../application.yaml" 
})
@ActiveProfiles("test")
public abstract class TestSupport{
}

- 테스트 클래스가 이 클래스를 상속 받게 하면 클래스 별로 Test Context를 설정할 필요가 없어짐.
- @ExtendWith : JUnit4의 @RunWith와 같은 역할을 하며, 테스트 클래스에 확장 모듈을 사용하게 한다.
- @SpringBootTest : Context Loader를 설정하는 어노테이션으로, SpringBootContextLoader를 기본으로 한다. 자동으로 설정 파일을 찾아 사용하고, 프로퍼티를 적용시킨다.
- @ActiveProfiles: 사용할 profile을 설정할 수 있다.

 

MockMvc

MockMvc는 server-side Spring MVC 테스트를 지원합니다.

 

- MockMvc를 사용하면 api 요청/응답을 테스트 로그에서 볼 수 있고, 각 요청이 처리되는 과정에서 생기는 debug level log를 확인할 수 있어 버그 추적에 용이
- 응답값은 MvcResult 객체에 담아야 함
- Assertion 없이 MockMvc perform 메서드 호출만으로 응답 status을 테스트할 수 있음

 

MockMvc 설정

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AutoConfigureMockMvc
@Import(EnableMockMvc.Config.class)
public @interface EnableMockMvc {
    class Config {
        @Bean
        public CharacterEncodingFilter characterEncodingFilter() {
            return new CharacterEncodingFilter("UTF-8", true);
        }
    }
}

설정할 게 많고, api 테스트 시 요청/응답 인코딩 이슈가 있어 위와 같이 커스텀 어노테이션을 만드는 것을 추천합니다.

 

MockMvc로 GET 테스트하기

- 파라미터 없는 경우

// GET
MvcResult mvcResult = mockMvc.perform(get("/test")
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())		// 예상 응답
  .andDo(print())					// 호출 결과 로깅
  .andReturn();						// 응답 결과(header+body)를 MvcResult로 반환

- 파라미터를 객체로 넘기는 경우

// param으로 넘겨줄 객체 세팅
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
// 객체를 key-value 형식의 파라미터로 변환
Map<String, String> map = objectMapper.convertValue(req, new TypeReference<>() {});
// 파라미터 등록
multiValueMap.setAll(map); 
// api 호출
MvcResult mvcResult = mockMvc.perform(get("/test")
  .params(multiValueMap)
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andDo(print())
  .andReturn();

 

MockMvc로 POST, PUT, DELETE 테스트하기

- body에 담을 객체는 ObjectMapper를 사용해 Stringfy시켜야 합니다.

// POST
mockMvc.perform(post("/test")
  .content(content)					// POST 요청 body (Stringfied Json)
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())		// 예상 응답
  .andDo(print());					// 호출 결과 로깅
  
// PUT
mockMvc.perform(put("/test")
  .content(content)					// PUT 요청 body (Stringfied Json)
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())		// 예상 응답
  .andDo(print());					// 호출 결과 로깅

// DELETE
mockMvc.perform(delete("/test")
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())		// 예상 응답
  .andDo(print());					// 호출 결과 로깅

 

Comments