@Valid와 BindingResult 또는 Errors

@PostMapping
public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto, Errors errors) {
	if (errors.hasErrors()) {
		return ResponseEntity.badRequest().build();
	}
	Event event = modelMapper.map(eventDto, Event.class);
	Event newEvent = eventRepository.save(event);
	URI createdUri = linkTo(EventController.class).slash(newEvent.getId()).toUri();
	return ResponseEntity.created(createdUri).body(newEvent);
}
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class EventDto {

	@NotEmpty
	private String name;
	@NotEmpty
	private String description;
	@NotNull
	private LocalDateTime beginEnrollmentDateTime;
	@NotNull
	private LocalDateTime closeEnrollmentDateTime;
	@NotNull
	private LocalDateTime beginEventDateTime;
	@NotNull
	private LocalDateTime endEventDateTime;
	private String location;
	@Min(0)
	private int basePrice;
	@Min(0)
	private int maxPrice;
	@Min(0)
	private int limitOfEnrollment;
}

도메인 Validator 만들기

@Component
public class EventValidator {

	public void validate(EventDto eventDto, Errors errors) {
		if (eventDto.getBasePrice() > eventDto.getMaxPrice() && eventDto.getMaxPrice() > 0) {
			errors.rejectValue("basePrice", "wrongValue", "BasePrice is wrong.");
			errors.rejectValue("maxPrice", "wrongValue", "maxPrice is wrong.");
		}

		LocalDateTime endEventDateTime = eventDto.getEndEventDateTime();
		if (endEventDateTime.isBefore(eventDto.getBeginEventDateTime())
		 || endEventDateTime.isBefore(eventDto.getCloseEnrollmentDateTime())
		 || endEventDateTime.isBefore(eventDto.getBeginEnrollmentDateTime())) {
			errors.rejectValue("endEventDateTime", "wrongValue", "EndEventDateTime is wrong");
		}
	}

	// TODO BeginEventDateTime
	// TODO CloseEnrollmentDateTime
}

테스트 설명용 애노테이션 만들기

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface TestDescription {

	String value();
}
@Test
@TestDescription("입력 값이 잘못되어 있는 경우에 에러가 발생하는 테스트")
public void createEvent_Bad_Request_Wrong_Input() throws Exception {