(1) deploy 하기 전에 테스트 단계에서 오류를 잡을 수 있다.
(2) 테스트를 할 수 있게 코드를 짜기 위해서 - 테스트를 할 수 있는 코드는 구조가 좋다
(3) 테스트 코드를 보는 것만으로도 코드가 어떻게 동작하는지 이해하기가 쉽다.
슬라이스 테스트
라고 한다. (1) @WebMvcTest: Controller를 테스트할 때 사용하는 annotation. 이 때 테스트하고자 하는 클래스를 명시해주지 않으면 @Controller, @RestController 등 컨트롤러와 관련된 bean 객체를 호출한다.
(2) @MockBean: 가짜 객체를 생성하도록 한다. Controller는 서비스 계층에 의존되어 있다. 따라서 Service 객체 대신에 가짜 객체를 생성하여 Service 객체의 역할을 대신 하도록 한다.
- Mockito의 given() 메서드를 이용해 가짜 객체에서 어떤 메서드가 호출되고 어떤 파라미터를 주입할 수 있는지를 설정할 수 있다.
- willReturn() 메서드를 통해 어떤 결과를 리턴할 것인지를 정할 수 있다.
(3) MockMvc: 서블릿 컨테이너를 구동하지 않고(웹 사이트를 띄우지 않고) 가상 환경에 모의로 url 요청을 보내서 컨트롤러가 제대로 작동하는지 테스트할 수 있도록 해준다.
@WebMvcTest(ArticleRestController.class)
class ArticleRestControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@MockBean
ArticleService articleService;
@Test
@DisplayName("reponse가 잘 오는지 확인")
void test1() throws Exception {
ArticleResponse articleResponse = ArticleResponse.builder()
.id(1L)
.content("첫번째게시글입니다")
.title("1번")
.build();
given(articleService.getArticle((long) 1))
.willReturn(articleResponse);
// 가짜 객체가 articleService의 getArticle() 메소드를 호출해서 id를 넣어주면
// articleResponse를 결과로 return하도록 한다.
long articleId = 1;
String url = String.format("/api/v1/articles/%d", articleId);
// perform() 메서드는 MockMvcRequestBuilders에서 제공하는 메서드를 이용해서 http 요청정보를 설정할 수 있다.
mockMvc.perform(get(url))
.andExpect(status().isOk()) // andExpect를 통해서 결과값을 검증할 수 있다.
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.title").value("1번"))
.andExpect(jsonPath("$.content").value("첫번째게시글입니다"))
.andDo(print()); // andDo() 메서드를 이용해서 요청과 응답의 전체 내용을 확인할 수 있다.
verify(articleService).getArticle(articleId);
// 메서드가 잘 실행되었는지 검증하는 역할
// default가 1, 뒤에 숫자를 넣어주면 몇 번 실행되었는지를 검증할 수 있다.
}
...
}
(1) post 요청할 때 @RequestBody의 값을 넘겨주기 위해 content()에 DTO의 값을 담아준다.
이 때 RequestBody는 보통 json 파일의 형태이므로 ObjectMapper의 writeValueAsByte()를 이용하거나 Gson의 toJson()을 이용해서 넘겨줄 수 있다.
@WebMvcTest(ArticleRestController.class)
class ArticleRestControllerTest {
...
@Test
@DisplayName("데이터를 잘 생성하는지 확인")
void test2() throws Exception {
ArticleAddRequest articleAddRequest = new ArticleAddRequest("제목", "내용");
given(articleService.addArticle(articleAddRequest))
.willReturn(new ArticleAddResponse(1L, articleAddRequest.getTitle(), articleAddRequest.getContent()));
mockMvc.perform(post("/api/v1/articles/add")
.content(objectMapper.writeValueAsBytes(articleAddRequest))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.title").value("제목"))
.andExpect(jsonPath("$.content").value("내용"))
.andDo(print());
verify(articleService).addArticle(articleAddRequest);
// articleService가 1번 이상 호출되었는지?
}
}
Gson gson = new Gson();
mockMvc.perform(post("/api/v1/articles/add")
.content(gson.toJson(articleAddRequest))
.contentType(MediaType.APPLICATION_JSON))
...