똑같은 삽질은 2번 하지 말자
Spring으로 REST API No.2(도메인구현, 기본 요청 응답(201)테스트, ) 본문
도메인 구현
@Builder
@AllArgsConstructor @NoArgsConstructor // public default 생성자
@Getter @Setter // @Data에는 EqualsAndHashCode가 기본적으로 정의되어있어서 겹침
@EqualsAndHashCode(of = "id")
// 기본적으로 객체의 모든 필드로 Equals, HashCode를 비교하는데 그럼
// 나중에 연관관계에서 (상호참조하는) StackOverFlow가 발생할 수 있으므로 ID로만 비교한다.
public class Event {
private Integer id;
private String name;
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional) 이게 없으면 온라인 모임
private int basePrice;
private int maxPrice;
private int limitOfEnrollment;
private boolean offline;
private boolean free;
private EventStatus eventStatus;
}
테스트
테스트 할 것
- 입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인.
- Location 헤더에 생성된 이벤트를 조회할 수 있는 URI 담겨 있는지 확인.
- id는 DB에 들어갈 때 자동생성된 값으로 나오는지 확인
ControllerTest
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.time.LocalDateTime;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(SpringRunner.class)
@WebMvcTest // slicing testing
public class EventControllerTests {
@Autowired
MockMvc mockMvc; // 요청 응답 을 만들어 줄 수 있는
@Autowired
ObjectMapper objectMapper;
@MockBean
EventRepository eventRepository; // 슬라이싱 테스트라 레포짓을 목으로 넣어준다.
@Test
public void createEvent() throws Exception {
Event event = Event.builder()
.name("Spring")
.description("REST API")
.beginEnrollmentDateTime(LocalDateTime.of(2020,6,28,14,11))
.closeEnrollmentDateTime(LocalDateTime.of(2020,6,28,14,11))
.beginEventDateTime(LocalDateTime.of(2020,6,28,14,11))
.endEventDateTime(LocalDateTime.of(2020,6,28,14,11))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("부산역 어딘가")
.build();
event.setId(10); // Mock은 null로 리턴되기 때문에
Mockito.when(eventRepository.save(event)).thenReturn(event); // 세입할 때 event를 리턴하겠다.
mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(print())
.andExpect(status().isCreated()) // 201 == isCreated
.andExpect(jsonPath("id").exists());
}
}
@WebMvcTest
- MockMvc 빈을 자동 설정 해준다. 따라서 그냥 가져와서 쓰면 됨.
- 웹 관련 빈만 등록해 준다. (슬라이스)
MockMvc
- 스프링 MVC 테스트 핵심 클래스
- 웹 서버를 띄우지 않고도 스프링 MVC (DispatcherServlet)가 요청을 처리하는 과정을 확인할 수 있기 때문에 컨트롤러 테스트용으로 자주 쓰임
ObjectMapper
- jackson 의존성을 등록하면 따로 선언없이 주입할 수 있는 친구
- 객체를 json문자열로 보낼때 쓰인다.
Controller
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.net.URI;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public class EventController {
@PostMapping
public ResponseEntity createEvent(@RequestBody Event event) {
URI createUri = linkTo(EventController.class).slash("{id}").toUri();
// 응답정보에 생성한 이벤트의조회uri담기
event.setId(10);
return ResponseEntity.created(createUri).body(event);
}
}
클래스 위에 RequestMapping을 정의함으로써 methodOn으로 굳이 uri를 찾을 필요가 없어졌다.
*참고로 linkTo 와 methodOn은 uri를 만들때 쓰이는 Hateoas 안에 있는 것인데 1.1? 이후로 없어졌으므로 주의바람
produces는 응답을 저 데이터 형태로 보내겠다.
Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface EventRepository extends JpaRepository<Event, Integer>{
}
HAL_JSON 형태
http://stateless.co/hal_specification.html
'Spring > Spring Boot' 카테고리의 다른 글
Spring으로 REST API No.4(Spring HATEOAS, ) (0) | 2020.07.02 |
---|---|
Spring으로 REST API No.3(입력값 제한, ModelMapper, @Valid, Errors, JsonSerializer ) (0) | 2020.06.29 |
Spring으로 REST API No.1(REST API , 프로젝트 구성) (0) | 2020.06.28 |
Spring Boot 개념다지기 No.20(Actuator) (0) | 2020.05.06 |
Spring Boot 개념다지기 No.19(RestClient) (0) | 2020.05.06 |
Comments