모르지 않다는 것은 아는것과 다르다.

Junit

WebMvc Test

채마스 2022. 2. 27. 01:46
@RunWith(SpringRunner.class)
@WebMvcTest
public class EventControllerTests {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void createEvent() throws Exception {
        mockMvc.perform(post("/api/events/")
                    .contentType(MediaType.APPLICATION_JSON_UTF8) //요청타입
                    .accept(MediaTypes.HAL_JSON)) //받고싶은 타입
                .andExpect(status().isCreated());
    }

}
  • MockMvc 클래스를 사용하면 스프링 MVC 테스트 핵심 클래스
  • mockMvc 를 사용하면 사용해서 가짜 요청을 만들어서 목킹이 되어있는 dispatcherServlet에 보낼 수 있다.
  • web과 관련된 빈들만 등록되기때문에 슬라이싱테스트라고 부른다.
  • 그렇기 때문에 좀더 빠르다. -> 단위 테스트라고 보긴 어렵다. -> 일단 디스팻쳐 서블릿만 가지고 있는것만으로도 너무 많은 것들이 개입되어있기 때문이다.
  • 웹서블릿을 만들지 않기때문에 빠르다. -> 하지만 단위테스트보단 느리다.



@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class EventController {

    private final EventRepository eventRepository;

    public EventController(EventRepository eventRepository) {
        this.eventRepository = eventRepository;
    }

    @PostMapping
    public ResponseEntity createEvent(@RequestBody Event event) {
        Event newEvent = this.eventRepository.save(event);
        //EventController의 id에 해당하는 링크를 만들고 링크를 URI로 변환
        //API에 events에 어떤 특정한 ID 그 ID가 생성된 이벤트에 Location Header에 들어감
        URI createdUri = linkTo(EventController.class).slash(newEvent.getId()).toUri();
        event.setId(10);
        // createdUri 헤더를 가지고 201응답을 만듬
        return ResponseEntity.created(createdUri).body(event);
    }
}
  • 위와 같이 결과값으로 body 에 event 객체를 문자로 반환해 주는 컨트롤러를 작성한다.



@RunWith(SpringRunner.class)
@WebMvcTest
public class EventControllerTests {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    // 슬라이싱 테스트라 Repository가 빈으로 등록되지 않아 MockBean을 지정
    // Mock 이라서 save 하는 값들이 전부 null
    @MockBean
    EventRepository eventRepository;

    @Test
    public void createEvent() throws Exception {
        Event event = Event.builder()
                .name("Spring")
                .description("REST API Development with Spring")
                .beginEnrollmentDateTime(LocalDateTime.of(2018, 11, 23, 14, 21))
                .closeEnrollmentDateTime(LocalDateTime.of(2018, 11, 24, 14, 21))
                .beginEventDateTime(LocalDateTime.of(2018, 11, 25, 14, 21))
                .endEventDateTime(LocalDateTime.of(2018, 11, 26, 14, 21))
                .basePrice(100)
                .maxPrice(200)
                .limitOfEnrollment(100)
                .location("강남역 D2 스타텁 팩토리")
                .build();
        //이벤트 ID 10으로 임의 설정
        event.setId(10);

        //eventRepository에 save가 호출되면 event를 리턴하라
        Mockito.when(eventRepository.save(event)).thenReturn(event);

        mockMvc.perform(post("/api/events/")
                    .contentType(MediaType.APPLICATION_JSON_UTF8) //요청타입
                    .accept(MediaTypes.HAL_JSON) //받고싶은 타입
                    .content(objectMapper.writeValueAsString(event))) //event를 json을 String으로 맵핑
                .andDo(print())
                .andExpect(status().isCreated()) // 201 상태인지 확인
                .andExpect(jsonPath("id").exists()) //ID가 있는지 확인
                .andExpect(header().exists(HttpHeaders.LOCATION)) // HEADER에 Location 있는지 확인
                .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE)); //Content-Type 값 확인
    }
}
  • 먼저 event 객체를 만들어준다.
  • Mockito.when(eventRepository.save(event)).thenReturn(event) : mock 은 기본적으로 null 을 반환하기 때문에 다음처럼 Stubbing 해줘야한다. -> 이게 싫으면 @SpringbootTest를 통해서 통합테스트를 해야한다.
  • contentType(MediaType.APPLICATION_JSON_UTF8) : 요청 타입을 지정한다.
  • accept(MediaTypes.HAL_JSON) : 응답 타입을 지정한다.
  • content(objectMapper.writeValueAsString(event))) : event를 json으로 매핑해서 content에 넣어준다.
    • 스프링부트를 사용하면 기본적으로 objectMapper를 제공한다.
  • print() 를 통해서 응답을 한눈에 볼 수 있다.
  • andExpect(status().isCreated()) : 201 상태인지 확인한다.
  • andExpect(jsonPath("id").exists()) : ID가 있는지 확인한다.




REFERENCES

  • 백기선님의 스프링 기반 REST API 개발

'Junit' 카테고리의 다른 글

파라미터를 사용해서 테스트하기  (0) 2022.02.27
테스트 더블  (0) 2022.02.27
단위테스트 vs 통합테스트  (0) 2022.02.27
Service 단위테스트  (0) 2022.02.27
Repository 단위테스트  (0) 2022.02.27