💐 Spring/Spring REST API

4) [test] 입력값 제한하기 (Bad_Request 발생) - 스프링 REST API

2020. 9. 9. 17:48
목차
  1. 테스트 할 것
  2. application.properties
  3. EventController.class
  4. EventDTO.class
  5. EventControllerTests.class
반응형

테스트 할 것

  • 입력값으로 누가 id나 eventStatus, offline, free 이런 데이터까지 같이 주면?
    • Bad_Request 발생 (이번 테스트!) vs 받기로 한 값 이외는 무시

핵심 코드

ObjectMapper 커스터마이징

 spring.jackson.deserialization.fail-on-unknown-properties = true
 // deserialization : 역직렬화(JSON -> 객체) 를 하는데, unknown-properties가 있으면 -> fail-on 실패를 던진다.

application.properties

spring.jackson.deserialization.fail-on-unknown-properties=true 
#왜 deserialization이냐면, (Json)EventDto를 (객체)Event에 넣어주는것이므로 비직렬화 이다.
# 객체 -> Json => Serialization
# Json -> 객체 => deSerialization 

EventController.class

package me.iseunghan.demoinflearnrestapi.events;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.net.URI;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@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()을 사용
        //HATEOAS가 제공하는 linkTo(), methodOn()을 사용 , 지금은 클래스레벨에 RequestMapping이 걸렸기때문에 methodOn 사용 X
        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;

//id 또는 입력 받은 데이터로 계산해야 하는 값들은 EventDTO로 입력값을 제한을 한다.
//Controller에서 ModelMapper로 EventDTO 객체를 받아서 Event객체로 매핑해주는 작업을 할것이다.
@Data @Builder @AllArgsConstructor @NoArgsConstructor
public class EventDto {

    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; // (optional)
    private int maxPrice; // (optional)
    private int limitOfEnrollment;
}

EventControllerTests.class

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventControllerTests {
    @Autowired
    MockMvc mockMvc;
    @Autowired
    ObjectMapper objectMapper;

 // TODO 받기로 한 값이 아닐때 -> Bad_Request로 응답
    //그대로 실행하면 에러 발생,
    // properties에 : spring.jackson.deserialization.fail-on-unknown-properties=true 를 추가해주면, unknown properties가 들어오면 fail -> error 발생!
    @Test
    public void createEvent_BadRequest() throws Exception {
        Event event = Event.builder()
                .id(100) // unknown properties
                .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)
                .free(true) // unknown properties
                .offline(false) // unknown properties
                .eventStatus(EventStatus.PUBLISHED) // unknown properties
                .build();


        mockMvc.perform(post("/api/events/")
                .contentType(MediaType.APPLICATION_JSON)//본문 요청에 json을 담아서 보내고 있다고 알려줌.
                .accept(MediaTypes.HAL_JSON)//HAL_JSON으로 받는다.
                .content(objectMapper.writeValueAsString(event)))//요청 본문에 넣어준다. objectMapper로 event를 json으로 변환후
                //이 부분에서 Controller에 @RequestBody로 넘기는 과정에서 EventDto에 modelmapping할때 unknown_properties인 값이 들어와서 테스트가 깨질것이다.
                .andDo(print())//어떤 응답과 요청을 받았는지 확인가능.
                .andExpect(status().isBadRequest())//badRequest요청이 들어왔는지?
                ;
    }

이해하기

Event 객체에다가 build(); 를 하는데 여기에는 EventDTO 에는 없는 값들도 같이 들어가있다.(id라던지, free,offline,eventStatus)

그 event객체를 가지고 .content(objectMapper.writeValueAsString(event))로 json으로 변환해서 -> post로 요청을 할때,
Event event = modelMapper.map(eventDto, Event.class); 여기서 eventDto 객체를 Event객체로 매핑을 할때,

Test에서 넘어온 JSON 데이터는 이렇다,

{
    "id" : 100, // X EventDTO 에는 없는 프로퍼티
    "name" : "Spring",
    "description" : "...",
    ...
    ...
    "eventStatus" : "EventStatus.PUBLISHED" // X EventDTO 에는 없는 프로퍼티
}

Event 값들을 EventDto 로 값들을 없는 값들은 무시하고 매핑시켜준다. 하지만 우리는 아까 application.properties 에서
우리가 커스터마이징 했던 spring.jackson.deserialization.fail-on-unknown-properties=true로 인해, unknown-properties가 있으므로, 테스트가 깨지게 된다.

반응형
저작자표시 (새창열림)
  1. 테스트 할 것
  2. application.properties
  3. EventController.class
  4. EventDTO.class
  5. EventControllerTests.class
'💐 Spring/Spring REST API' 카테고리의 다른 글
  • 6) [test] Bad_Request 응답 본문 만들기 - 스프링 REST API
  • 5) [test] 입력값 제한하기 (비즈니스 로직으로 검사) - 스프링 REST API
  • 3) [test] 입력값 제한하기 (무시하는 방법) - 스프링 REST API
  • 2) [test] JSON 응답으로 201이 나오는지 확인 - 스프링 REST API
iseunghan
iseunghan
꾸준하게 열심히..
iseunghan
iseunghan

공지사항

  • 어제보다 나은 오늘이 되기 위해 🔥
  • 분류 전체보기 (262)
    • 💐 Spring (14)
      • 개념 및 이해 (2)
      • Spring 핵심 기술 (24)
      • Spring REST API (8)
      • Spring MVC, DB 접근 기술 (7)
      • Spring Security (23)
      • Spring in Action (1)
    • 🌻 JAVA (84)
      • 자바 ORM 표준 JPA 프로그래밍 (20)
      • 알고리즘, 자료구조 (13)
      • 디자인 패턴 (7)
      • 정리정리정리 (43)
      • JUnit (1)
    • 🔖 Snippets (3)
      • Javascript (3)
    • ⚙️ Devops (22)
      • ⛏ Git (11)
      • 🐳 Docker (6)
      • 🐧 Linux (3)
      • 🌈 Jenkins (1)
      • 📬 Kafka (1)
    • 💬 ETC.. (4)
      • 💻 macOS (2)
    • 🌧️ ORM (2)
      • JPA (2)
    • 🐍 Python (3)
    • 📚 Databases (15)
      • 오라클로 배우는 데이터베이스 개론과 실습(2판) (3)
      • RealMySQL 8.0 (8)
    • 🔥 Computer Science (5)
      • 📡 네트워크 (5)
    • 🏷️ 협업 (1)
    • 📜 코딩테스트 (38)
      • BAEKJOON\수학 1, 수학 2 (8)
      • BAEKJOON\재귀 (5)
      • BAEKJOON\브루트 포스 (3)
      • BAEKJOON\정렬 (1)
      • BAEKJOON\백트래킹 (5)
      • BAEKJOON\BFS, DFS (6)
      • BAEKJOON\이분탐색 (1)
      • BAEKJOON\다이나믹 프로그래밍 (9)
      • BAEKJOON\그리디 알고리즘 (0)
    • ✨ ISEUNGHAN (1)

인기 글

최근 글

전체
오늘
어제
반응형
hELLO · Designed By 정상우.
iseunghan
4) [test] 입력값 제한하기 (Bad_Request 발생) - 스프링 REST API
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.