๋ฐ์ํ
ํ ์คํธ ํ ๊ฒ
- ์
๋ ฅ๊ฐ์ผ๋ก ๋๊ฐ id๋ eventStatus, offline, free ์ด๋ฐ ๋ฐ์ดํฐ๊น์ง ๊ฐ์ด ์ฃผ๋ฉด?
- Bad_Request ๋ก ์๋ต vs ๋ฐ๊ธฐ๋ก ํ ๊ฐ ์ด์ธ๋ ๋ฌด์! (์ด๋ฒ ํ ์คํธ ๋ฐฉ๋ฒ)
์ ๋ ฅ๊ฐ ์ ํ
- id ๋๋ ์ ๋ ฅ ๋ฐ์ ๋ฐ์ดํฐ๋ก ๊ณ์ฐํด์ผ ํ๋ ๊ฐ๋ค์ ์ ๋ ฅ ๋ฐ์ง ์์์ผ ํ๋ค.
- EventDTO ์ ์ฉ
DTO -> ๋๋ฉ์ธ ๊ฐ์ฒด๋ก ๊ฐ ๋ณต์ฌ
- ModelMapper
์์กด์ฑ ์ถ๊ฐ
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.1</version>
</dependency>
๋น์ผ๋ก ๋ฑ๋ก
@Configuration ์๋์
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
ํตํฉ ํ ์คํธ๋ก ์ ํ
- @WebMvcTest ๋นผ๊ณ ๋ค์ ์ ๋
ธํ
์ด์
์ถ๊ฐ
- @SpringBootTest
- @AutoConfigureMockMvc
- Repository @MockBean ์ฝ๋ ์ ๊ฑฐ
EventController.class
@Controller
@RequestMapping(value = "/api/events", produces = MediaTypes.HAL_JSON_VALUE)
public class EventController {
private final EventRepository eventRepository;
private final ModelMapper modelMapper;
//์์ฑ์๊ฐ ํ๋๋ง์๊ณ , ๋ฐ์์ฌ ํ์
์ด ๋น์ผ๋ก ๋ฑ๋ก๋์ด์์ผ๋ฉด autowired ์๋ต ๊ฐ๋ฅ
public EventController(EventRepository eventRepository, ModelMapper modelMapper) {
this.eventRepository = eventRepository;
this.modelMapper = modelMapper;
}
@PostMapping
public ResponseEntity createEvent(@RequestBody EventDto eventDto) {
/*Event event = Event.builder()
.name(eventDto.getName())
...
.build(); ๋ฅผ ์์ฝ๊ฒ ๋งคํํด์ฃผ๋ ModelMapper๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.*/
Event event = modelMapper.map(eventDto, Event.class);
Event newEvent = this.eventRepository.save(event);
//link๋ฅผ ์์ฑํ ๋,
//HATEOAS๊ฐ ์ ๊ณตํ๋ linkTo(), methodOn()์ ์ฌ์ฉ
URI createUri = linkTo(EventController.class).slash(newEvent.getId()).toUri();
return ResponseEntity.created(createUri).body(event); //201์๋ต์ Uri์ ๋ด์์ ๋ฆฌํด์ํจ๋ค.
}
}
EventDTO.class
package me.iseunghan.demoinflearnrestapi.events;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data @Builder @AllArgsConstructor @NoArgsConstructor
public class EventDto {
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional) ์ด๊ฒ ์์ผ๋ฉด ์จ๋ผ์ธ ๋ชจ์
private int basePrice; // (optional)
private int maxPrice; // (optional)
private int limitOfEnrollment;
}
EventControllerTests.class
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventControllerTests {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
public void createEvent() throws Exception {
Event event = Event.builder()
.id(100)
.name("Spring")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2020, 9, 7, 2, 45))
.closeEnrollmentDateTime(LocalDateTime.of(2020, 9, 8, 2, 45))
.beginEventDateTime(LocalDateTime.of(2020, 9, 9, 2, 45))
.endEventDateTime(LocalDateTime.of(2020, 9, 10, 2, 45))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("Daejoen")
.free(true)
.offline(false)
.eventStatus(EventStatus.PUBLISHED)
.build();
//Mock๊ฐ์ฒด๋ก ๋ฐ์๊ธฐ ๋๋ฌธ์ save๋ ์๋ ๊ฒ์ด๊ณ , NullpointerException์ด ๋ฐ์ํ ๊ฒ์ด๋ค.
//๊ทธ๋ฆฌํ์ฌ Mockito.when(eventRepository.save(event)).thenReturn(event);
//eventRepository.save๊ฐ ํธ์ถ์ด ๋๋ฉด -> ๊ทธ๋ค์ event๋ฅผ ๋ฆฌํดํ๋ผ.
//Mockito.when(eventRepository.save(event)).thenReturn(event);
mockMvc.perform(post("/api/events/")
.contentType(MediaType.APPLICATION_JSON)//๋ณธ๋ฌธ ์์ฒญ์ json์ ๋ด์์ ๋ณด๋ด๊ณ ์๋ค๊ณ ์๋ ค์ค.
.accept(MediaTypes.HAL_JSON)//HAL_JSON์ผ๋ก ๋ฐ๋๋ค.
.content(objectMapper.writeValueAsString(event)))//์์ฒญ ๋ณธ๋ฌธ์ ๋ฃ์ด์ค๋ค. objectMapper๋ก event๋ฅผ json์ผ๋ก ๋ณํํ
.andDo(print())//์ด๋ค ์๋ต๊ณผ ์์ฒญ์ ๋ฐ์๋์ง ํ์ธ๊ฐ๋ฅ.
.andExpect(status().isCreated())//201์์ฒญ์ด ๋ค์ด์๋์ง?
.andExpect(jsonPath("id").exists()) //json์ id๊ฐ ์๋์ง?
.andExpect(header().exists(HttpHeaders.LOCATION))//ํค๋์ Location์ด ์๋์ง
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_VALUE))//content-type์ "application/hal+json"๊ฐ ๋์ค๋์ง?
.andExpect(jsonPath("id").value(Matchers.not(100)))
.andExpect(jsonPath("free").value(Matchers.not(true)))
.andExpect(jsonPath("eventStatus").value(EventStatus.PUBLISHED.name()))
;
}
}
์ด๋ฒ ํ
์คํธ๋ @WebMvcTest ๊ฐ ์๋, @SpringBootTest ์ด๊ธฐ ๋๋ฌธ์ ์ง์ง ์คํ๋ง์ ๋์์ @SpringBootApplication ํจํค์ง์
๋ชจ๋ ๋น๋ค์ ๋ฑ๋ก์์ผ์ค๋ค. ๊ทธ๋ฌ๋ฏ๋ก, Mockito๊ฐ ์๋! Controller์์ ์ง์ repository.save๋ฅผ ์์ผ์ฃผ๋ฉด ๋๋ค.
๋ฐ์ํ