From 046f5d4eba79436c7f0a7ddd5b799595e8e75e0b Mon Sep 17 00:00:00 2001 From: Guga Date: Thu, 14 Sep 2023 14:49:39 +0900 Subject: [PATCH] =?UTF-8?q?[BE]=20feat:=20validation=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(#113)=20(#365)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 어노테이션 기반의 Spring validation 추가 * feat: 도메인 validation 추가 * feat: lineUp 은 null 일 수 있다. * feat: dto validation 추가 * feat: MethodArgumentNotValidException 에 대한 custom 핸들링 * feat: dto 의 예외 메시지 지정한다 * fix: Member 의 profileImage 가 null 인 경우의 null check 제거 * feat: length 검증 전 null check 가 선행되도록 변경 * refactor: Objects.isNull -> == null 확인으로 변경 * feat: Service Entity 생성 로직 삭제 * feat: socialType Enumerated 추가 * feat: @RequestBody validate 추가 * feat: dto @Valid 실패시 400 response --- .../com/festago/auth/dto/LoginRequest.java | 5 ++- .../java/com/festago/domain/Festival.java | 41 +++++++++++++++++- .../main/java/com/festago/domain/Member.java | 42 +++++++++++++++++- .../java/com/festago/domain/MemberTicket.java | 29 +++++++++++++ .../main/java/com/festago/domain/Stage.java | 43 +++++++++++++++++-- .../main/java/com/festago/domain/Ticket.java | 15 +++++++ .../java/com/festago/domain/TicketAmount.java | 14 ++++++ .../com/festago/domain/TicketEntryTime.java | 32 +++++++++++--- .../java/com/festago/dto/ErrorResponse.java | 10 +++++ .../festago/dto/FestivalCreateRequest.java | 12 +++--- .../com/festago/dto/StageCreateRequest.java | 9 ++-- .../com/festago/dto/TicketCreateRequest.java | 11 +++-- .../festago/dto/TicketValidationRequest.java | 4 +- .../com/festago/dto/TicketingRequest.java | 4 +- .../java/com/festago/exception/ErrorCode.java | 1 + .../festago/presentation/AdminController.java | 13 +++--- .../presentation/GlobalExceptionHandler.java | 11 +++++ .../presentation/MemberTicketController.java | 3 +- .../StaffMemberTicketController.java | 3 +- .../presentation/StudentController.java | 3 +- .../festago/domain/TicketEntryTimeTest.java | 21 ++++++--- 21 files changed, 283 insertions(+), 43 deletions(-) diff --git a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java index f34f17bed..8f82722aa 100644 --- a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java +++ b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java @@ -1,7 +1,10 @@ package com.festago.auth.dto; import com.festago.auth.domain.SocialType; +import jakarta.validation.constraints.NotNull; -public record LoginRequest(SocialType socialType, String accessToken) { +public record LoginRequest( + @NotNull(message = "socialType 은 null 일 수 없습니다.") SocialType socialType, + @NotNull(message = "acessToken 은 null 일 수 없습니다.") String accessToken) { } diff --git a/backend/src/main/java/com/festago/domain/Festival.java b/backend/src/main/java/com/festago/domain/Festival.java index 088c4d080..2c72c9460 100644 --- a/backend/src/main/java/com/festago/domain/Festival.java +++ b/backend/src/main/java/com/festago/domain/Festival.java @@ -6,6 +6,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDate; import java.time.LocalDateTime; @@ -18,12 +20,18 @@ public class Festival extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull + @Size(max = 50) private String name; + @NotNull private LocalDate startDate; + @NotNull private LocalDate endDate; + @NotNull + @Size(max = 255) private String thumbnail; protected Festival() { @@ -38,7 +46,7 @@ public Festival(String name, LocalDate startDate, LocalDate endDate, String thum } public Festival(Long id, String name, LocalDate startDate, LocalDate endDate, String thumbnail) { - validate(startDate, endDate); + validate(name, startDate, endDate, thumbnail); this.id = id; this.name = name; this.startDate = startDate; @@ -46,7 +54,36 @@ public Festival(Long id, String name, LocalDate startDate, LocalDate endDate, St this.thumbnail = thumbnail; } - private void validate(LocalDate startDate, LocalDate endDate) { + private void validate(String name, LocalDate startDate, LocalDate endDate, String thumbnail) { + checkNotNull(name, startDate, endDate, thumbnail); + checkLength(name, thumbnail); + validateDate(startDate, endDate); + } + + private void checkNotNull(String name, LocalDate startDate, LocalDate endDate, String thumbnail) { + if (name == null || + startDate == null || + endDate == null || + thumbnail == null) { + throw new IllegalArgumentException("Festival 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String name, String thumbnail) { + if (overLength(name, 50) || + overLength(thumbnail, 255)) { + throw new IllegalArgumentException("Festival 의 필드로 허용된 길이를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + + private void validateDate(LocalDate startDate, LocalDate endDate) { if (startDate.isAfter(endDate)) { throw new BadRequestException(ErrorCode.INVALID_FESTIVAL_DURATION); } diff --git a/backend/src/main/java/com/festago/domain/Member.java b/backend/src/main/java/com/festago/domain/Member.java index 2aefd4b7c..4b657e6d1 100644 --- a/backend/src/main/java/com/festago/domain/Member.java +++ b/backend/src/main/java/com/festago/domain/Member.java @@ -7,6 +7,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; @@ -17,18 +19,25 @@ public class Member extends BaseTimeEntity { private static final String DEFAULT_IMAGE_URL = "https://festa-go.site/images/default-profile.png"; - + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull + @Size(max = 255) private String socialId; - @Enumerated(EnumType.STRING) + @NotNull + @Enumerated(value = EnumType.STRING) private SocialType socialType; + @NotNull + @Size(max = 30) private String nickname; + @NotNull + @Size(max = 255) private String profileImage; private LocalDateTime deletedAt = null; @@ -45,6 +54,7 @@ public Member(String socialId, SocialType socialType, String nickname, String pr } public Member(Long id, String socialId, SocialType socialType, String nickname, String profileImage) { + validate(socialId, socialType, nickname, profileImage); this.id = id; this.socialId = socialId; this.socialType = socialType; @@ -52,6 +62,34 @@ public Member(Long id, String socialId, SocialType socialType, String nickname, this.profileImage = (profileImage != null) ? profileImage : DEFAULT_IMAGE_URL; } + private void validate(String socialId, SocialType socialType, String nickname, String profileImage) { + checkNotNull(socialId, socialType, nickname); + checkLength(socialId, nickname, profileImage); + } + + private void checkNotNull(String socialId, SocialType socialType, String nickname) { + if (socialId == null || + socialType == null || + nickname == null) { + throw new IllegalArgumentException("Member 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String socialId, String nickname, String profileImage) { + if (overLength(socialId, 255) || + overLength(nickname, 30) || + overLength(profileImage, 255)) { + throw new IllegalArgumentException("Member 의 필드로 허용된 길이를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + public Long getId() { return id; } diff --git a/backend/src/main/java/com/festago/domain/MemberTicket.java b/backend/src/main/java/com/festago/domain/MemberTicket.java index a79aea13e..ce741075c 100644 --- a/backend/src/main/java/com/festago/domain/MemberTicket.java +++ b/backend/src/main/java/com/festago/domain/MemberTicket.java @@ -8,6 +8,8 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Objects; @@ -20,19 +22,25 @@ public class MemberTicket extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull @Enumerated(EnumType.STRING) private EntryState entryState = EntryState.BEFORE_ENTRY; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Member owner; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Stage stage; + @Min(value = 0) private int number; + @NotNull private LocalDateTime entryTime; + @NotNull @Enumerated(EnumType.STRING) private TicketType ticketType; @@ -45,6 +53,7 @@ public MemberTicket(Member owner, Stage stage, int number, LocalDateTime entryTi public MemberTicket(Long id, Member owner, Stage stage, int number, LocalDateTime entryTime, TicketType ticketType) { + validate(owner, stage, number, entryTime, ticketType); this.id = id; this.owner = owner; this.stage = stage; @@ -53,6 +62,26 @@ public MemberTicket(Long id, Member owner, Stage stage, int number, LocalDateTim this.ticketType = ticketType; } + private void validate(Member owner, Stage stage, int number, LocalDateTime entryTime, TicketType ticketType) { + checkNotNull(owner, stage, entryTime, ticketType); + checkScope(number); + } + + private void checkNotNull(Member owner, Stage stage, LocalDateTime entryTime, TicketType ticketType) { + if (owner == null || + stage == null || + entryTime == null || + ticketType == null) { + throw new IllegalArgumentException("MemberTicket 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkScope(int number) { + if (number < 0) { + throw new IllegalArgumentException("MemberTicket 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + } + public void changeState(EntryState originState) { if (originState != this.entryState) { return; diff --git a/backend/src/main/java/com/festago/domain/Stage.java b/backend/src/main/java/com/festago/domain/Stage.java index af2a3c299..933475dbd 100644 --- a/backend/src/main/java/com/festago/domain/Stage.java +++ b/backend/src/main/java/com/festago/domain/Stage.java @@ -2,7 +2,6 @@ import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; -import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -10,6 +9,8 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -21,13 +22,16 @@ public class Stage extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) + @NotNull private LocalDateTime startTime; + @Size(max = 255) private String lineUp; + @NotNull private LocalDateTime ticketOpenTime; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Festival festival; @@ -41,9 +45,13 @@ public Stage(LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTim this(null, startTime, lineUp, ticketOpenTime, festival); } + public Stage(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + this(null, startTime, null, ticketOpenTime, festival); + } + public Stage(Long id, LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTime, Festival festival) { - validate(startTime, ticketOpenTime, festival); + validate(startTime, lineUp, ticketOpenTime, festival); this.id = id; this.startTime = startTime; this.lineUp = lineUp; @@ -51,7 +59,34 @@ public Stage(Long id, LocalDateTime startTime, String lineUp, LocalDateTime tick this.festival = festival; } - private void validate(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + private void validate(LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTime, Festival festival) { + checkNotNull(startTime, ticketOpenTime, festival); + checkLength(lineUp); + validateTime(startTime, ticketOpenTime, festival); + } + + private void checkNotNull(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + if (startTime == null || + ticketOpenTime == null || + festival == null) { + throw new IllegalArgumentException("Stage 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String lineUp) { + if (overLength(lineUp, 255)) { + throw new IllegalArgumentException("Stage 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + + private void validateTime(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { if (festival.isNotInDuration(startTime)) { throw new BadRequestException(ErrorCode.INVALID_STAGE_START_TIME); } diff --git a/backend/src/main/java/com/festago/domain/Ticket.java b/backend/src/main/java/com/festago/domain/Ticket.java index 2b078e292..326c2c1bc 100644 --- a/backend/src/main/java/com/festago/domain/Ticket.java +++ b/backend/src/main/java/com/festago/domain/Ticket.java @@ -14,6 +14,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Set; import java.util.SortedSet; @@ -29,9 +30,11 @@ public class Ticket extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Stage stage; + @NotNull @Enumerated(EnumType.STRING) private TicketType ticketType; @@ -51,12 +54,24 @@ public Ticket(Stage stage, TicketType ticketType) { } public Ticket(Long id, Stage stage, TicketType ticketType) { + validate(stage, ticketType); this.id = id; this.stage = stage; this.ticketType = ticketType; this.ticketAmount = new TicketAmount(this); } + private void validate(Stage stage, TicketType ticketType) { + checkNotNull(stage, ticketType); + } + + private void checkNotNull(Stage stage, TicketType ticketType) { + if (stage == null || + ticketType == null) { + throw new IllegalArgumentException("Ticket 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + public void addTicketEntryTime(LocalDateTime currentTime, LocalDateTime entryTime, int amount) { validateEntryTime(currentTime, entryTime); TicketEntryTime ticketEntryTime = new TicketEntryTime(entryTime, amount); diff --git a/backend/src/main/java/com/festago/domain/TicketAmount.java b/backend/src/main/java/com/festago/domain/TicketAmount.java index 7d55fb1a1..03d4a91db 100644 --- a/backend/src/main/java/com/festago/domain/TicketAmount.java +++ b/backend/src/main/java/com/festago/domain/TicketAmount.java @@ -8,6 +8,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.MapsId; import jakarta.persistence.OneToOne; +import jakarta.validation.constraints.Min; @Entity public class TicketAmount extends BaseTimeEntity { @@ -15,8 +16,10 @@ public class TicketAmount extends BaseTimeEntity { @Id private Long id; + @Min(value = 0) private int reservedAmount = 0; + @Min(value = 0) private int totalAmount = 0; @OneToOne(fetch = FetchType.LAZY) @@ -28,9 +31,20 @@ protected TicketAmount() { } public TicketAmount(Ticket ticket) { + validate(ticket); this.ticket = ticket; } + private void validate(Ticket ticket) { + checkNotNull(ticket); + } + + private void checkNotNull(Ticket ticket) { + if (ticket == null) { + throw new IllegalArgumentException("TicketAmount 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + public void increaseReservedAmount() { if (reservedAmount >= totalAmount) { throw new BadRequestException(ErrorCode.TICKET_SOLD_OUT); diff --git a/backend/src/main/java/com/festago/domain/TicketEntryTime.java b/backend/src/main/java/com/festago/domain/TicketEntryTime.java index 3994251df..e495a07d4 100644 --- a/backend/src/main/java/com/festago/domain/TicketEntryTime.java +++ b/backend/src/main/java/com/festago/domain/TicketEntryTime.java @@ -6,6 +6,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; @Entity @@ -17,25 +19,45 @@ public class TicketEntryTime extends BaseTimeEntity implements Comparable createFestival(@RequestBody FestivalCreateRequest request) { + public ResponseEntity createFestival(@RequestBody @Valid FestivalCreateRequest request) { FestivalResponse response = festivalService.create(request); return ResponseEntity.ok() .body(response); } @PostMapping("/stages") - public ResponseEntity createStage(@RequestBody StageCreateRequest request) { + public ResponseEntity createStage(@RequestBody @Valid StageCreateRequest request) { StageResponse response = stageService.create(request); return ResponseEntity.ok() .body(response); } @PostMapping("/tickets") - public ResponseEntity createTicket(@RequestBody TicketCreateRequest request) { + public ResponseEntity createTicket(@RequestBody @Valid TicketCreateRequest request) { TicketCreateResponse response = ticketService.create(request); return ResponseEntity.ok() .body(response); @@ -96,7 +97,7 @@ public ModelAndView loginPage() { } @PostMapping("/login") - public ResponseEntity login(@RequestBody AdminLoginRequest request) { + public ResponseEntity login(@RequestBody @Valid AdminLoginRequest request) { String token = adminAuthService.login(request); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, getCookie(token)) .build(); @@ -140,7 +141,7 @@ public ResponseEntity getInfo() { } @PostMapping("/initialize") - public ResponseEntity initializeRootAdmin(@RequestBody RootAdminInitializeRequest request) { + public ResponseEntity initializeRootAdmin(@RequestBody @Valid RootAdminInitializeRequest request) { adminAuthService.initializeRootAdmin(request.password()); return ResponseEntity.ok() .build(); @@ -152,7 +153,7 @@ public ModelAndView signupPage() { } @PostMapping("/signup") - public ResponseEntity signupAdminAccount(@RequestBody AdminSignupRequest request, + public ResponseEntity signupAdminAccount(@RequestBody @Valid AdminSignupRequest request, @Admin Long adminId) { AdminSignupResponse response = adminAuthService.signup(adminId, request); return ResponseEntity.ok() diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index 9fcf38b75..866b119cc 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -11,10 +11,14 @@ import com.festago.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @RestControllerAdvice @@ -93,6 +97,13 @@ public ResponseEntity handle(Exception e, HttpServletRequest requ .body(ErrorResponse.from(ErrorCode.INTERNAL_SERVER_ERROR)); } + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, + HttpStatusCode status, WebRequest request) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ErrorResponse.from(ErrorCode.INVALID_REQUEST_ARGUMENT)); + } + private void logInfo(FestaGoException e, HttpServletRequest request) { if (errorLogger.isInfoEnabled()) { errorLogger.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), diff --git a/backend/src/main/java/com/festago/presentation/MemberTicketController.java b/backend/src/main/java/com/festago/presentation/MemberTicketController.java index 9ceee591d..1319d954f 100644 --- a/backend/src/main/java/com/festago/presentation/MemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/MemberTicketController.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -53,7 +54,7 @@ public ResponseEntity createQR(@Member Long memberId, @PostMapping @Operation(description = "티켓을 예매한다.", summary = "티켓 예매") public ResponseEntity ticketing(@Member Long memberId, - @RequestBody TicketingRequest request) { + @RequestBody @Valid TicketingRequest request) { TicketingResponse response = ticketingService.ticketing(memberId, request); return ResponseEntity.ok() .body(response); diff --git a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java index d3aeedd3b..cf969b956 100644 --- a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java @@ -6,6 +6,7 @@ import com.festago.dto.TicketValidationResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -25,7 +26,7 @@ public StaffMemberTicketController(EntryService entryService) { @PostMapping("/validation") @Operation(description = "스태프가 티켓을 검사한다.", summary = "티켓 검사") - public ResponseEntity validate(@RequestBody TicketValidationRequest request) { + public ResponseEntity validate(@RequestBody @Valid TicketValidationRequest request) { TicketValidationResponse response = entryService.validate(request); return ResponseEntity.ok() .body(response); diff --git a/backend/src/main/java/com/festago/presentation/StudentController.java b/backend/src/main/java/com/festago/presentation/StudentController.java index 7f0c1270a..462c87cb3 100644 --- a/backend/src/main/java/com/festago/presentation/StudentController.java +++ b/backend/src/main/java/com/festago/presentation/StudentController.java @@ -6,6 +6,7 @@ import com.festago.dto.StudentVerificateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -35,7 +36,7 @@ public ResponseEntity sendEmail(@Member Long memberId, @PostMapping("/verification") @Operation(description = "학교 인증을 수행한다.", summary = "학생 인증 수행") public ResponseEntity verificate(@Member Long memberId, - @RequestBody StudentVerificateRequest request) { + @RequestBody @Valid StudentVerificateRequest request) { studentService.verificate(memberId, request); return ResponseEntity.ok() .build(); diff --git a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java index 32bfbc5c0..e1c283290 100644 --- a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java +++ b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java @@ -6,21 +6,30 @@ import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; @DisplayNameGeneration(ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class TicketEntryTimeTest { - @ParameterizedTest - @ValueSource(ints = {0, -1}) - void 총_수량이_1_미만이면_예외(int totalAmount) { + @Test + void 총_수량이_음수일_경우_에외() { // given LocalDateTime now = LocalDateTime.now(); // when & then - assertThatThrownBy(() -> new TicketEntryTime(now, totalAmount)) + assertThatThrownBy(() -> new TicketEntryTime(now, -1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TicketEntryTime 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + + @Test + void 총_수량이_1_미만이면_예외() { + // given + LocalDateTime now = LocalDateTime.now(); + + // when & then + assertThatThrownBy(() -> new TicketEntryTime(now, 0)) .isInstanceOf(BadRequestException.class) .hasMessage("티켓은 적어도 한장 이상 발급해야합니다."); }