MockMvc란?
웹 어플리케이션의 서버를 띠우지 않아도 스프링 MVC의 동작을 재현할 수 있게해준다.
MockMvc는 Test 메소드에서 DispatcherServlet에 보내야할 요청을 대신 요청해줍니다. 그리고 이때 DispatcherServlet의 sub-class인 TestDispatcherServlet으로 요청을 보내서 응답을 MvcResult로 저장합니다. TestDispatcherServlet은 요청에 맞는 handler로 연결해주고 exception처리들도 이루어집니다.
실습
Controller
@RestController public class PostController { PostService postService; public PostController(PostService postService) { this.postService = postService; } @PostMapping("/posts") public ResponseEntity<ApiResponse<Long>> createPost(@RequestBody PostDto postDto) { Long save = postService.save(postDto); return new ResponseEntity<>(ApiResponse.created(save), HttpStatus.CREATED); } }
ControllerTest
@SpringBootTest @AutoConfigureMockMvc @AutoConfigureRestDocs @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(Lifecycle.PER_CLASS) @Slf4j class PostControllerTest { @Autowired MockMvc mockMvc; @Autowired ObjectMapper objectMapper; @Autowired PostController postController; @Autowired PostRepository postRepository; @Autowired UserRepository userRepository; @Test @Order(1) @DisplayName("포스트를 생성할 수 있다.") void save_post_test() throws Exception { UserDto userDto = new UserDto("suy2on", 25, "reading book"); PostDto postDto = new PostDto("my-post", "this is my first post.", userDto); mockMvc.perform(post("/posts") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(postDto))) .andExpect(status().isCreated()) .andDo(print()) .andDo(document("save-post", requestFields( fieldWithPath("title").type(JsonFieldType.STRING).description("title"), fieldWithPath("content").type(JsonFieldType.STRING).description("content"), fieldWithPath("userDto").type(JsonFieldType.OBJECT).description("userDto"), fieldWithPath("userDto.name").type(JsonFieldType.STRING) .description("userDto.name"), fieldWithPath("userDto.age").type(JsonFieldType.NUMBER) .description("userDto.age"), fieldWithPath("userDto.hobby").type(JsonFieldType.STRING) .description("userDto.hobby") ), responseFields( fieldWithPath("code").type(JsonFieldType.NUMBER).description("상태코드"), fieldWithPath("data").type(JsonFieldType.NUMBER).description("데이터"), fieldWithPath("timestamp").type(JsonFieldType.STRING).description("응답시간") ) )); } }
perform
DispatcherServlet에 요청을 보냅니다.
RequestBuilder
를 받고 ResultAction
을 반환합니다.post
넘겨받은 URL과 Method에 맞는
MockHttpServletRequestBuilder
를 반환합니다MockHttpServletRequestBuilder
contentType
, content
, header
, cookie
와 같은 메소드로 요청에 설정을 해줄 수 있습니다.ResultAction
그렇게
perform
으로 부터 넘겨받은 ResultAction
은 다시 andDo
, andExpect
와 같은 메소드들로 원하는 처리를 해줄 수 있습니다.andExpect
특히
andExpect
는 ResultMatcher
들을 받아서 예상한 것과 반환값을 비교해줍니다.andDo(print())
MockMvc에서 요청에 대한 처리가 일어난 과정을 출력해줍니다
MockHttpServletRequest: HTTP Method = POST Request URI = /posts Parameters = {} Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"114"] Body = {"title":"my-post","content":"this is my first post.","userDto":{"name":"suy2on","age":25,"hobby":"reading book"}} Session Attrs = {} Handler: Type = com.prgrms.springbootboardjpa.controller.PostController Method = com.prgrms.springbootboardjpa.controller.PostController#createPost(PostDto) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 201 Error message = null Headers = [Content-Type:"application/json"] Content type = application/json Body = {"code":201,"data":1,"timestamp":"2022-05-22 17:32:10"} Forwarded URL = null Redirected URL = null Cookies = []
정리하면 아래와 같습니다
