From 12275e0144125538b7347bc702927a1ff7b9a1e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=8D=ED=98=81=EC=A4=80?= <31675711+HyuckJuneHong@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:21:36 +0900 Subject: [PATCH] =?UTF-8?q?refactor=20:=20=EC=BF=A0=ED=8F=B0=20=EB=B0=9C?= =?UTF-8?q?=ED=96=89=20=EA=B8=B0=EA=B0=84=20=ED=95=98=EB=A3=A8=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=BF=A0=ED=8F=B0=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=98=A4=ED=94=88=20=EB=82=A0=EC=A7=9C=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=20=EC=B6=94=EA=B0=80=20(#136)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style : Schedule 어노테이션 위치 변경 * refactor: 쿠폰 발행 기간 하루로 통일 및 쿠폰 정보 오픈 날짜 추가 * refactor: Sub module Update --- .../api/application/coupon/CouponMapper.java | 4 +- .../api/application/coupon/CouponService.java | 26 ++-- .../com/moabam/api/domain/coupon/Coupon.java | 16 +-- .../repository/CouponSearchRepository.java | 48 ++----- .../moabam/api/dto/coupon/CouponResponse.java | 10 +- .../api/dto/coupon/CouponStatusRequest.java | 3 +- .../api/dto/coupon/CreateCouponRequest.java | 10 +- .../com/moabam/global/config/FcmConfig.java | 2 - .../com/moabam/global/config/WebConfig.java | 2 + .../global/error/model/ErrorMessage.java | 5 +- src/main/resources/config | 2 +- src/main/resources/static/docs/coupon.html | 121 +++--------------- .../resources/static/docs/notification.html | 2 +- .../coupon/CouponQueueServiceTest.java | 15 ++- .../application/coupon/CouponServiceTest.java | 83 +++++++----- .../moabam/api/domain/coupon/CouponTest.java | 10 +- .../CouponSearchRepositoryTest.java | 110 ++++------------ .../dto/coupon/CreateCouponRequestTest.java | 8 +- .../presentation/CouponControllerTest.java | 72 +++++++---- .../moabam/support/fixture/CouponFixture.java | 75 +++++++---- .../support/fixture/CouponSnippetFixture.java | 17 ++- 21 files changed, 270 insertions(+), 371 deletions(-) diff --git a/src/main/java/com/moabam/api/application/coupon/CouponMapper.java b/src/main/java/com/moabam/api/application/coupon/CouponMapper.java index f61a6c3c..d38dbb77 100644 --- a/src/main/java/com/moabam/api/application/coupon/CouponMapper.java +++ b/src/main/java/com/moabam/api/application/coupon/CouponMapper.java @@ -19,7 +19,7 @@ public static Coupon toEntity(Long adminId, CreateCouponRequest coupon) { .point(coupon.point()) .stock(coupon.stock()) .startAt(coupon.startAt()) - .endAt(coupon.endAt()) + .openAt(coupon.openAt()) .adminId(adminId) .build(); } @@ -35,7 +35,7 @@ public static CouponResponse toDto(Coupon coupon) { .stock(coupon.getStock()) .type(coupon.getType()) .startAt(coupon.getStartAt()) - .endAt(coupon.getEndAt()) + .openAt(coupon.getOpenAt()) .build(); } } diff --git a/src/main/java/com/moabam/api/application/coupon/CouponService.java b/src/main/java/com/moabam/api/application/coupon/CouponService.java index f0f72f34..0d080df4 100644 --- a/src/main/java/com/moabam/api/application/coupon/CouponService.java +++ b/src/main/java/com/moabam/api/application/coupon/CouponService.java @@ -1,6 +1,6 @@ package com.moabam.api.application.coupon; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; import org.springframework.stereotype.Service; @@ -35,7 +35,7 @@ public class CouponService { public void create(AuthMember admin, CreateCouponRequest request) { validateAdminRole(admin); validateConflictName(request.name()); - validatePeriod(request.startAt(), request.endAt()); + validatePeriod(request.startAt(), request.openAt()); Coupon coupon = CouponMapper.toEntity(admin.id(), request); couponRepository.save(coupon); @@ -57,7 +57,7 @@ public CouponResponse getById(Long couponId) { } public List getAllByStatus(CouponStatusRequest request) { - LocalDateTime now = clockHolder.times(); + LocalDate now = LocalDate.from(clockHolder.times()); List coupons = couponSearchRepository.findAllByStatus(now, request); return coupons.stream() @@ -66,20 +66,26 @@ public List getAllByStatus(CouponStatusRequest request) { } public Coupon validatePeriod(String couponName) { - LocalDateTime now = clockHolder.times(); + LocalDate now = LocalDate.from(clockHolder.times()); Coupon coupon = couponRepository.findByName(couponName) .orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON)); - if (!now.isBefore(coupon.getStartAt()) && !now.isAfter(coupon.getEndAt())) { - return coupon; + if (!now.equals(coupon.getStartAt())) { + throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD); } - throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD_END); + return coupon; } - private void validatePeriod(LocalDateTime startAt, LocalDateTime endAt) { - if (startAt.isAfter(endAt)) { - throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD); + private void validatePeriod(LocalDate startAt, LocalDate openAt) { + LocalDate now = LocalDate.from(clockHolder.times()); + + if (!now.isBefore(startAt)) { + throw new BadRequestException(ErrorMessage.INVALID_COUPON_START_AT_PERIOD); + } + + if (!openAt.isBefore(startAt)) { + throw new BadRequestException(ErrorMessage.INVALID_COUPON_OPEN_AT_PERIOD); } } diff --git a/src/main/java/com/moabam/api/domain/coupon/Coupon.java b/src/main/java/com/moabam/api/domain/coupon/Coupon.java index c3e5c2be..daeda469 100644 --- a/src/main/java/com/moabam/api/domain/coupon/Coupon.java +++ b/src/main/java/com/moabam/api/domain/coupon/Coupon.java @@ -4,7 +4,7 @@ import static com.moabam.global.error.model.ErrorMessage.*; import static java.util.Objects.*; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.Optional; import org.hibernate.annotations.ColumnDefault; @@ -56,25 +56,25 @@ public class Coupon extends BaseTimeEntity { private int stock; @Column(name = "start_at", nullable = false) - private LocalDateTime startAt; + private LocalDate startAt; - @Column(name = "end_at", nullable = false) - private LocalDateTime endAt; + @Column(name = "open_at", nullable = false) + private LocalDate openAt; // TODO : 관리자 테이블 생기면 관리자 테이블이랑 다대일 관계 맺을 예정 @Column(name = "admin_id", updatable = false, nullable = false) private Long adminId; @Builder - private Coupon(String name, int point, String description, CouponType type, int stock, LocalDateTime startAt, - LocalDateTime endAt, Long adminId) { + private Coupon(String name, String description, int point, int stock, CouponType type, LocalDate startAt, + LocalDate openAt, Long adminId) { this.name = requireNonNull(name); this.point = validatePoint(point); this.description = Optional.ofNullable(description).orElse(BLANK); this.type = requireNonNull(type); this.stock = validateStock(stock); this.startAt = requireNonNull(startAt); - this.endAt = requireNonNull(endAt); + this.openAt = requireNonNull(openAt); this.adminId = requireNonNull(adminId); } @@ -96,6 +96,6 @@ private int validateStock(int stock) { @Override public String toString() { - return "Coupon{startAt=" + startAt + ", endAt=" + endAt + '}'; + return String.format("Coupon{startAt=%s, openAt=%s}", startAt, openAt); } } diff --git a/src/main/java/com/moabam/api/domain/coupon/repository/CouponSearchRepository.java b/src/main/java/com/moabam/api/domain/coupon/repository/CouponSearchRepository.java index 7a922d2a..703847eb 100644 --- a/src/main/java/com/moabam/api/domain/coupon/repository/CouponSearchRepository.java +++ b/src/main/java/com/moabam/api/domain/coupon/repository/CouponSearchRepository.java @@ -2,7 +2,7 @@ import static com.moabam.api.domain.coupon.QCoupon.*; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; import org.springframework.stereotype.Repository; @@ -10,7 +10,6 @@ import com.moabam.api.domain.coupon.Coupon; import com.moabam.api.dto.coupon.CouponStatusRequest; import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -21,51 +20,30 @@ public class CouponSearchRepository { private final JPAQueryFactory jpaQueryFactory; - public List findAllByStatus(LocalDateTime now, CouponStatusRequest couponStatus) { + public List findAllByStatus(LocalDate now, CouponStatusRequest couponStatus) { return jpaQueryFactory.selectFrom(coupon) .where(filterStatus(now, couponStatus)) + .orderBy(coupon.startAt.asc()) .fetch(); } - private BooleanExpression filterStatus(LocalDateTime now, CouponStatusRequest couponStatus) { - if (couponStatus.ongoing() && couponStatus.notStarted() && couponStatus.ended()) { + private BooleanExpression filterStatus(LocalDate now, CouponStatusRequest couponStatus) { + // 모든 쿠폰 (금일 발급 가능한 쿠폰 포함) + if (couponStatus.opened() && couponStatus.ended()) { return null; } - // 시작 전이거나 진행 중인 쿠폰들을 조회하고 싶은 경우 - if (couponStatus.ongoing() && couponStatus.notStarted()) { - return (coupon.startAt.gt(now)) - .or(coupon.startAt.loe(now).and(coupon.endAt.goe(now))); + // 쿠폰 정보 오픈 중인 쿠폰들 (금일 발급 가능한 쿠폰 포함) + if (couponStatus.opened()) { + return coupon.openAt.loe(now).and(coupon.startAt.goe(now)); } - // 종료 됐거나 진행 중인 쿠폰들을 조회하고 싶은 경우 - if (couponStatus.ongoing() && couponStatus.ended()) { - return (coupon.endAt.lt(now)) - .or(coupon.startAt.loe(now).and(coupon.endAt.goe(now))); - } - - // 진행 중이 아니고, 시작 전이거나, 종료된 쿠폰들을 조회하고 싶은 경우 - if (couponStatus.notStarted() && couponStatus.ended()) { - return coupon.startAt.gt(now) - .or(coupon.endAt.lt(now)); - } - - // 진행 중인 쿠폰들을 조회하고 싶은 경우 - if (couponStatus.ongoing()) { - return coupon.startAt.loe(now) - .and(coupon.endAt.goe(now)); - } - - // 시작 적인 쿠폰들을 조회하고 싶은 경우 - if (couponStatus.notStarted()) { - return coupon.startAt.gt(now); - } - - // 종료된 쿠폰들을 조회하고 싶은 경우 + // 종료된 쿠폰들 if (couponStatus.ended()) { - return coupon.endAt.lt(now); + return coupon.startAt.lt(now); } - return Expressions.FALSE; + // 금일 발급 가능한 쿠폰 + return coupon.startAt.eq(now); } } diff --git a/src/main/java/com/moabam/api/dto/coupon/CouponResponse.java b/src/main/java/com/moabam/api/dto/coupon/CouponResponse.java index 0a323acd..ac408733 100644 --- a/src/main/java/com/moabam/api/dto/coupon/CouponResponse.java +++ b/src/main/java/com/moabam/api/dto/coupon/CouponResponse.java @@ -1,6 +1,6 @@ package com.moabam.api.dto.coupon; -import java.time.LocalDateTime; +import java.time.LocalDate; import com.fasterxml.jackson.annotation.JsonFormat; import com.moabam.api.domain.coupon.CouponType; @@ -16,10 +16,10 @@ public record CouponResponse( int point, int stock, CouponType type, - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm") - LocalDateTime startAt, - @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm") - LocalDateTime endAt + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate startAt, + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate openAt ) { } diff --git a/src/main/java/com/moabam/api/dto/coupon/CouponStatusRequest.java b/src/main/java/com/moabam/api/dto/coupon/CouponStatusRequest.java index 0c41fcdb..0cecaea2 100644 --- a/src/main/java/com/moabam/api/dto/coupon/CouponStatusRequest.java +++ b/src/main/java/com/moabam/api/dto/coupon/CouponStatusRequest.java @@ -4,8 +4,7 @@ @Builder public record CouponStatusRequest( - boolean ongoing, - boolean notStarted, + boolean opened, boolean ended ) { diff --git a/src/main/java/com/moabam/api/dto/coupon/CreateCouponRequest.java b/src/main/java/com/moabam/api/dto/coupon/CreateCouponRequest.java index 245ff76e..02ebc0c7 100644 --- a/src/main/java/com/moabam/api/dto/coupon/CreateCouponRequest.java +++ b/src/main/java/com/moabam/api/dto/coupon/CreateCouponRequest.java @@ -1,6 +1,6 @@ package com.moabam.api.dto.coupon; -import java.time.LocalDateTime; +import java.time.LocalDate; import org.hibernate.validator.constraints.Length; @@ -18,10 +18,10 @@ public record CreateCouponRequest( @NotBlank(message = "쿠폰 종류를 입력해주세요.") String type, @Min(value = 1, message = "벌레 수 혹은 할인 금액은 1 이상이어야 합니다.") int point, @Min(value = 1, message = "쿠폰 재고는 1 이상이어야 합니다.") int stock, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm") - @NotNull(message = "쿠폰 발급 시작 시각을 입력해주세요.") LocalDateTime startAt, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm") - @NotNull(message = "쿠폰 발급 종료 시각을 입력해주세요.") LocalDateTime endAt + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + @NotNull(message = "쿠폰 발급이 가능한 날짜(년, 월, 일)를 입력해주세요.") LocalDate startAt, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + @NotNull(message = "쿠폰 정보창이 열리는 날짜(년, 월, 일)를 입력해주세요.") LocalDate openAt ) { } diff --git a/src/main/java/com/moabam/global/config/FcmConfig.java b/src/main/java/com/moabam/global/config/FcmConfig.java index 115e6091..6f003820 100644 --- a/src/main/java/com/moabam/global/config/FcmConfig.java +++ b/src/main/java/com/moabam/global/config/FcmConfig.java @@ -6,7 +6,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; -import org.springframework.scheduling.annotation.EnableScheduling; import com.google.auth.oauth2.GoogleCredentials; import com.google.firebase.FirebaseApp; @@ -19,7 +18,6 @@ @Slf4j @Configuration -@EnableScheduling public class FcmConfig { private static final String FIREBASE_PATH = "config/moabam-firebase.json"; diff --git a/src/main/java/com/moabam/global/config/WebConfig.java b/src/main/java/com/moabam/global/config/WebConfig.java index e2296881..b72e98af 100644 --- a/src/main/java/com/moabam/global/config/WebConfig.java +++ b/src/main/java/com/moabam/global/config/WebConfig.java @@ -6,6 +6,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -15,6 +16,7 @@ import com.moabam.global.auth.handler.PathResolver; @Configuration +@EnableScheduling public class WebConfig implements WebMvcConfigurer { private static final String ALLOWED_METHOD_NAMES = "GET,HEAD,POST,PUT,DELETE,TRACE,OPTIONS,PATCH"; diff --git a/src/main/java/com/moabam/global/error/model/ErrorMessage.java b/src/main/java/com/moabam/global/error/model/ErrorMessage.java index 351450fe..a0fdf88e 100644 --- a/src/main/java/com/moabam/global/error/model/ErrorMessage.java +++ b/src/main/java/com/moabam/global/error/model/ErrorMessage.java @@ -63,8 +63,9 @@ public enum ErrorMessage { INVALID_COUPON_POINT("쿠폰의 보너스 포인트는 0 이상이어야 합니다."), INVALID_COUPON_STOCK("쿠폰의 재고는 0 이상이어야 합니다."), INVALID_COUPON_STOCK_END("쿠폰 발급 선착순이 마감되었습니다."), - INVALID_COUPON_PERIOD("쿠폰 발급 종료 시각은 시작 시각보다 이후여야 합니다."), - INVALID_COUPON_PERIOD_END("쿠폰 발급 가능 기간이 아닙니다."), + INVALID_COUPON_START_AT_PERIOD("쿠폰 발급 시작 날짜는 현재 날짜보다 이전이거나 같을 수 없습니다."), + INVALID_COUPON_OPEN_AT_PERIOD("쿠폰 정보 오픈 날짜는 시작 날짜보다 이전이여야 합니다."), + INVALID_COUPON_PERIOD("쿠폰 발급 가능 기간이 아닙니다."), CONFLICT_COUPON_NAME("쿠폰의 이름이 중복되었습니다."), NOT_FOUND_COUPON_TYPE("존재하지 않는 쿠폰 종류입니다."), NOT_FOUND_COUPON("존재하지 않는 쿠폰입니다."), diff --git a/src/main/resources/config b/src/main/resources/config index 2a1a59a1..35c04d25 160000 --- a/src/main/resources/config +++ b/src/main/resources/config @@ -1 +1 @@ -Subproject commit 2a1a59a16d8e868185c125a58aec0682f3c53f0d +Subproject commit 35c04d25c466b163ffceaf81b5d7e8855b78d7ec diff --git a/src/main/resources/static/docs/coupon.html b/src/main/resources/static/docs/coupon.html index c8ede223..df366758 100644 --- a/src/main/resources/static/docs/coupon.html +++ b/src/main/resources/static/docs/coupon.html @@ -461,7 +461,7 @@

요청

POST /admins/coupons HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Content-Length: 186
+Content-Length: 175
 Host: localhost:8080
 
 {
@@ -470,8 +470,8 @@ 

요청

"type" : "황금", "point" : 10, "stock" : 10, - "startAt" : "2023-01-01T00:00", - "endAt" : "2023-02-01T00:00" + "startAt" : "2023-02-01", + "openAt" : "2023-01-01" }
@@ -496,7 +496,7 @@

쿠폰 삭제

요청

-
DELETE /admins/coupons/11 HTTP/1.1
+
DELETE /admins/coupons/1 HTTP/1.1
 Host: localhost:8080
@@ -534,7 +534,7 @@

응답

Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json -Content-Length: 216 +Content-Length: 205 { "id" : 26, @@ -544,8 +544,8 @@

응답

"point" : 10, "stock" : 100, "type" : "MORNING_COUPON", - "startAt" : "2023-01-01T00:00", - "endAt" : "2023-02-01T00:00" + "startAt" : "2023-02-01", + "openAt" : "2023-01-01" }
@@ -565,13 +565,12 @@

요청

POST /coupons/search HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Content-Length: 63
+Content-Length: 41
 Host: localhost:8080
 
 {
-  "ongoing" : true,
-  "notStarted" : true,
-  "ended" : true
+  "opened" : false,
+  "ended" : false
 }
@@ -583,108 +582,18 @@

응답

Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json -Content-Length: 2153 +Content-Length: 206 [ { - "id" : 14, - "adminName" : "1admin", - "name" : "coupon1", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-01-01T00:00", - "endAt" : "2023-03-01T00:00" -}, { "id" : 15, "adminName" : "1admin", - "name" : "coupon2", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-02-01T00:00", - "endAt" : "2023-04-01T00:00" -}, { - "id" : 16, - "adminName" : "1admin", - "name" : "coupon3", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-03-01T00:00", - "endAt" : "2023-05-01T00:00" -}, { - "id" : 17, - "adminName" : "1admin", - "name" : "coupon4", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-04-01T00:00", - "endAt" : "2023-06-01T00:00" -}, { - "id" : 18, - "adminName" : "1admin", - "name" : "coupon5", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-05-01T00:00", - "endAt" : "2023-07-01T00:00" -}, { - "id" : 19, - "adminName" : "1admin", - "name" : "coupon6", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-06-01T00:00", - "endAt" : "2023-08-01T00:00" -}, { - "id" : 20, - "adminName" : "1admin", - "name" : "coupon7", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-07-01T00:00", - "endAt" : "2023-09-01T00:00" -}, { - "id" : 21, - "adminName" : "1admin", - "name" : "coupon8", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-08-01T00:00", - "endAt" : "2023-10-01T00:00" -}, { - "id" : 22, - "adminName" : "1admin", - "name" : "coupon9", - "description" : "", - "point" : 10, - "stock" : 100, - "type" : "MORNING_COUPON", - "startAt" : "2023-09-01T00:00", - "endAt" : "2023-11-01T00:00" -}, { - "id" : 23, - "adminName" : "1admin", - "name" : "coupon10", + "name" : "coupon1", "description" : "", "point" : 10, "stock" : 100, "type" : "MORNING_COUPON", - "startAt" : "2023-10-01T00:00", - "endAt" : "2023-12-01T00:00" + "startAt" : "2023-03-01", + "openAt" : "2023-01-01" } ] @@ -707,7 +616,7 @@

요청

Host: localhost:8080 Content-Length: 21 -couponName=CouponName +couponName=couponName

응답

diff --git a/src/main/resources/static/docs/notification.html b/src/main/resources/static/docs/notification.html index 72056746..67060c84 100644 --- a/src/main/resources/static/docs/notification.html +++ b/src/main/resources/static/docs/notification.html @@ -515,7 +515,7 @@

응답

diff --git a/src/test/java/com/moabam/api/application/coupon/CouponQueueServiceTest.java b/src/test/java/com/moabam/api/application/coupon/CouponQueueServiceTest.java index cd33635d..b6721d68 100644 --- a/src/test/java/com/moabam/api/application/coupon/CouponQueueServiceTest.java +++ b/src/test/java/com/moabam/api/application/coupon/CouponQueueServiceTest.java @@ -35,10 +35,10 @@ class CouponQueueServiceTest { @WithMember @DisplayName("쿠폰 발급 요청을 성공적으로 큐에 등록한다. - Void") @Test - void couponQueueService_register() { + void register() { // Given AuthMember member = AuthorizationThreadLocal.getAuthMember(); - Coupon coupon = CouponFixture.coupon("couponName", 1, 2); + Coupon coupon = CouponFixture.coupon(); given(couponService.validatePeriod(any(String.class))).willReturn(coupon); given(couponQueueRepository.size(any(String.class))).willReturn(coupon.getStock() - 1L); @@ -53,25 +53,26 @@ void couponQueueService_register() { @WithMember @DisplayName("해당 쿠폰은 발급 가능 기간이 아니다. - BadRequestException") @Test - void couponQueueService_register_BadRequestException() { + void register_BadRequestException() { // Given AuthMember member = AuthorizationThreadLocal.getAuthMember(); + given(couponService.validatePeriod(any(String.class))) - .willThrow(new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD_END)); + .willThrow(new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD)); // When & Then assertThatThrownBy(() -> couponQueueService.register(member, "couponName")) .isInstanceOf(BadRequestException.class) - .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD_END.getMessage()); + .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD.getMessage()); } @WithMember @DisplayName("해당 쿠폰은 마감된 쿠폰이다. - Void") @Test - void couponQueueService_register_End() { + void register_End() { // Given AuthMember member = AuthorizationThreadLocal.getAuthMember(); - Coupon coupon = CouponFixture.coupon("couponName", 1, 2); + Coupon coupon = CouponFixture.coupon(); given(couponService.validatePeriod(any(String.class))).willReturn(coupon); given(couponQueueRepository.size(any(String.class))).willReturn((long)coupon.getStock()); diff --git a/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java b/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java index 266d5915..18099a8c 100644 --- a/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java +++ b/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.BDDMockito.*; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -53,13 +54,13 @@ class CouponServiceTest { @WithMember(role = Role.ADMIN) @DisplayName("쿠폰을 성공적으로 발행한다. - Void") @Test - void couponService_createCoupon() { + void create() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); - String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); given(couponRepository.existsByName(any(String.class))).willReturn(false); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); // When couponService.create(admin, request); @@ -71,11 +72,10 @@ void couponService_createCoupon() { @WithMember(role = Role.USER) @DisplayName("권한 없는 사용자가 쿠폰을 발행한다. - NotFoundException") @Test - void couponService_createCoupon_Admin_NotFoundException() { + void create_Admin_NotFoundException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); - String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); // When & Then assertThatThrownBy(() -> couponService.create(admin, request)) @@ -83,14 +83,30 @@ void couponService_createCoupon_Admin_NotFoundException() { .hasMessage(ErrorMessage.MEMBER_NOT_FOUND.getMessage()); } + @WithMember(role = Role.ADMIN) + @DisplayName("존재하지 않는 쿠폰 종류를 발행한다. - NotFoundException") + @Test + void create_Type_NotFoundException() { + // Given + AuthMember admin = AuthorizationThreadLocal.getAuthMember(); + CreateCouponRequest request = CouponFixture.createCouponRequest("UNKNOWN", 2, 1); + + given(couponRepository.existsByName(any(String.class))).willReturn(false); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); + + // When & Then + assertThatThrownBy(() -> couponService.create(admin, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage(ErrorMessage.NOT_FOUND_COUPON_TYPE.getMessage()); + } + @WithMember(role = Role.ADMIN) @DisplayName("중복된 쿠폰명을 발행한다. - ConflictException") @Test - void couponService_createCoupon_ConflictException() { + void create_ConflictException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); - String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); given(couponRepository.existsByName(any(String.class))).willReturn(true); @@ -101,40 +117,44 @@ void couponService_createCoupon_ConflictException() { } @WithMember(role = Role.ADMIN) - @DisplayName("존재하지 않는 쿠폰 종류를 발행한다. - NotFoundException") + @DisplayName("현재 날짜가 쿠폰 발급 가능 날짜와 같거나 이후이다. - BadRequestException") @Test - void couponService_createCoupon_NotFoundException() { + void create_StartAt_BadRequestException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); - CreateCouponRequest request = CouponFixture.createCouponRequest("UNKNOWN", 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); + + given(clockHolder.times()).willReturn(LocalDateTime.of(2025, 1, 1, 1, 1)); given(couponRepository.existsByName(any(String.class))).willReturn(false); // When & Then assertThatThrownBy(() -> couponService.create(admin, request)) - .isInstanceOf(NotFoundException.class) - .hasMessage(ErrorMessage.NOT_FOUND_COUPON_TYPE.getMessage()); + .isInstanceOf(BadRequestException.class) + .hasMessage(ErrorMessage.INVALID_COUPON_START_AT_PERIOD.getMessage()); } @WithMember(role = Role.ADMIN) - @DisplayName("쿠폰 발급 종료 기간이 시작 기간보다 더 이전인 쿠폰을 발행한다. - BadRequestException") + @DisplayName("쿠폰 정보 오픈 날짜가 쿠폰 발급 시작 날짜와 같거나 이후인 쿠폰을 발행한다. - BadRequestException") @Test - void couponService_createCoupon_BadRequestException() { + void create_OpenAt_BadRequestException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 2, 1); + CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 1); + given(couponRepository.existsByName(any(String.class))).willReturn(false); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); // When & Then assertThatThrownBy(() -> couponService.create(admin, request)) .isInstanceOf(BadRequestException.class) - .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD.getMessage()); + .hasMessage(ErrorMessage.INVALID_COUPON_OPEN_AT_PERIOD.getMessage()); } @WithMember(role = Role.ADMIN) @DisplayName("쿠폰 아이디와 일치하는 쿠폰을 삭제한다. - Void") @Test - void couponService_deleteCoupon() { + void delete() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); Coupon coupon = CouponFixture.coupon(10, 100); @@ -150,7 +170,7 @@ void couponService_deleteCoupon() { @WithMember(role = Role.USER) @DisplayName("권한 없는 사용자가 쿠폰을 삭제한다. - NotFoundException") @Test - void couponService_deleteCoupon_Admin_NotFoundException() { + void delete_Admin_NotFoundException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); @@ -163,7 +183,7 @@ void couponService_deleteCoupon_Admin_NotFoundException() { @WithMember(role = Role.ADMIN) @DisplayName("존재하지 않는 쿠폰 아이디를 삭제하려고 시도한다. - NotFoundException") @Test - void couponService_deleteCoupon_NotFoundException() { + void delete_NotFoundException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); given(couponRepository.findById(any(Long.class))).willReturn(Optional.empty()); @@ -176,7 +196,7 @@ void couponService_deleteCoupon_NotFoundException() { @DisplayName("특정 쿠폰을 조회한다. - CouponResponse") @Test - void couponService_getCouponById() { + void getById() { // Given Coupon coupon = CouponFixture.coupon(10, 100); given(couponRepository.findById(any(Long.class))).willReturn(Optional.of(coupon)); @@ -191,7 +211,7 @@ void couponService_getCouponById() { @DisplayName("존재하지 않는 쿠폰을 조회한다. - NotFoundException") @Test - void couponService_getCouponById_NotFoundException() { + void getById_NotFoundException() { // Given given(couponRepository.findById(any(Long.class))).willReturn(Optional.empty()); @@ -204,12 +224,13 @@ void couponService_getCouponById_NotFoundException() { @DisplayName("모든 쿠폰을 조회한다. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void couponService_getCoupons(List coupons) { + void getAllByStatus(List coupons) { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true, true); - given(couponSearchRepository.findAllByStatus(any(LocalDateTime.class), any(CouponStatusRequest.class))) - .willReturn(coupons); + CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false); + given(clockHolder.times()).willReturn(LocalDateTime.now()); + given(couponSearchRepository.findAllByStatus(any(LocalDate.class), any(CouponStatusRequest.class))) + .willReturn(coupons); // When List actual = couponService.getAllByStatus(request); @@ -220,7 +241,7 @@ void couponService_getCoupons(List coupons) { @DisplayName("해당 쿠폰은 발급 가능 기간입니다. - Coupon") @Test - void couponService_validateCouponPeriod() { + void validatePeriod() { // Given LocalDateTime now = LocalDateTime.of(2023, 1, 1, 1, 0); Coupon coupon = CouponFixture.coupon("couponName", 1, 2); @@ -236,7 +257,7 @@ void couponService_validateCouponPeriod() { @DisplayName("해당 쿠폰은 발급 가능 기간이 아닙니다. - BadRequestException") @Test - void couponService_validateCouponPeriod_BadRequestException() { + void validatePeriod_BadRequestException() { // Given LocalDateTime now = LocalDateTime.of(2022, 1, 1, 1, 0); Coupon coupon = CouponFixture.coupon("couponName", 1, 2); @@ -246,12 +267,12 @@ void couponService_validateCouponPeriod_BadRequestException() { // When & Then assertThatThrownBy(() -> couponService.validatePeriod("couponName")) .isInstanceOf(BadRequestException.class) - .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD_END.getMessage()); + .hasMessage(ErrorMessage.INVALID_COUPON_PERIOD.getMessage()); } @DisplayName("해당 쿠폰은 존재하지 않습니다. - NotFoundException") @Test - void couponService_validateCouponPeriod_NotFoundException() { + void validatePeriod_NotFoundException() { // Given LocalDateTime now = LocalDateTime.of(2022, 1, 1, 1, 0); given(couponRepository.findByName(any(String.class))).willReturn(Optional.empty()); diff --git a/src/test/java/com/moabam/api/domain/coupon/CouponTest.java b/src/test/java/com/moabam/api/domain/coupon/CouponTest.java index 29d27f45..2ab0e438 100644 --- a/src/test/java/com/moabam/api/domain/coupon/CouponTest.java +++ b/src/test/java/com/moabam/api/domain/coupon/CouponTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.*; -import java.time.LocalDateTime; +import java.time.LocalDate; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -17,8 +17,8 @@ class CouponTest { @Test void coupon() { // Given - LocalDateTime startAt = LocalDateTime.of(2000, 1, 22, 10, 30, 0); - LocalDateTime endAt = LocalDateTime.of(2000, 1, 22, 11, 0, 0); + LocalDate startAt = LocalDate.of(2023, 2, 1); + LocalDate openAt = LocalDate.of(2023, 1, 1); // When Coupon actual = Coupon.builder() @@ -27,7 +27,7 @@ void coupon() { .type(CouponType.MORNING_COUPON) .stock(100) .startAt(startAt) - .endAt(endAt) + .openAt(openAt) .adminId(1L) .build(); @@ -38,7 +38,7 @@ void coupon() { assertThat(actual.getStock()).isEqualTo(100); assertThat(actual.getType()).isEqualTo(CouponType.MORNING_COUPON); assertThat(actual.getStartAt()).isEqualTo(startAt); - assertThat(actual.getEndAt()).isEqualTo(endAt); + assertThat(actual.getOpenAt()).isEqualTo(openAt); assertThat(actual.getAdminId()).isEqualTo(1L); } diff --git a/src/test/java/com/moabam/api/domain/coupon/repository/CouponSearchRepositoryTest.java b/src/test/java/com/moabam/api/domain/coupon/repository/CouponSearchRepositoryTest.java index 92994bd1..22deb4da 100644 --- a/src/test/java/com/moabam/api/domain/coupon/repository/CouponSearchRepositoryTest.java +++ b/src/test/java/com/moabam/api/domain/coupon/repository/CouponSearchRepositoryTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.*; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -27,13 +27,13 @@ class CouponSearchRepositoryTest { @Autowired private CouponSearchRepository couponSearchRepository; - @DisplayName("모든 쿠폰을 조회한다. - List") + @DisplayName("발급 가능한 쿠폰을 조회한다. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void couponSearchRepository_findAllByStatus(List coupons) { + void findAllByStatus(List coupons) { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true, true); - LocalDateTime now = LocalDateTime.now(); + CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false); + LocalDate now = LocalDate.of(2023, 7, 1); couponRepository.saveAll(coupons); @@ -41,50 +41,17 @@ void couponSearchRepository_findAllByStatus(List coupons) { List actual = couponSearchRepository.findAllByStatus(now, request); // Then - assertThat(actual).hasSize(coupons.size()); - } - - @DisplayName("시작 전이거나 진행 중인 쿠폰들을 조회한다. - List") - @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") - @ParameterizedTest - void couponSearchRepository_findAllByStatus_and_ongoing_notStarted(List coupons) { - // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true, false); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); - - couponRepository.saveAll(coupons); - - // When - List actual = couponSearchRepository.findAllByStatus(now, request); - - // Then - assertThat(actual).hasSize(8); - } - - @DisplayName("종료 됐거나 진행 중인 쿠폰들을 조회한다. - List") - @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") - @ParameterizedTest - void couponSearchRepository_findAllByStatus_and_ongoing_ended(List coupons) { - // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, false, true); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); - - couponRepository.saveAll(coupons); - - // When - List actual = couponSearchRepository.findAllByStatus(now, request); - - // Then - assertThat(actual).hasSize(5); + assertThat(actual).hasSize(1); + assertThat(actual.get(0).getStartAt()).isEqualTo(LocalDate.of(2023, 7, 1)); } - @DisplayName("진행 중이 아니고, 시작 전이거나, 종료된 쿠폰들을 조회한다. - List") + @DisplayName("모든 쿠폰을 발급 가능 날짜 순으로 조회한다. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void couponSearchRepository_findAllByStatus_ongoing_and_ended(List coupons) { + void findAllByStatus_order_by_startAt(List coupons) { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(false, true, true); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); + CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true); + LocalDate now = LocalDate.now(); couponRepository.saveAll(coupons); @@ -92,16 +59,17 @@ void couponSearchRepository_findAllByStatus_ongoing_and_ended(List coupo List actual = couponSearchRepository.findAllByStatus(now, request); // Then - assertThat(actual).hasSize(7); + assertThat(actual).hasSize(coupons.size()); + assertThat(actual.get(0).getStartAt()).isEqualTo(LocalDate.of(2023, 3, 1)); } - @DisplayName("진행 중인 쿠폰을 조회한다. - List") + @DisplayName("발급 가능한 쿠폰 포함하여 쿠폰 정보 오픈 중인 쿠폰들을 발급 가능 날짜 순으로 조회한다. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void couponSearchRepository_findAllByStatus_ongoing(List coupons) { + void findAllByStatus_opened_order_by_startAt(List coupons) { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, false, false); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); + CouponStatusRequest request = CouponFixture.couponStatusRequest(true, false); + LocalDate now = LocalDate.of(2023, 7, 1); couponRepository.saveAll(coupons); @@ -110,15 +78,16 @@ void couponSearchRepository_findAllByStatus_ongoing(List coupons) { // Then assertThat(actual).hasSize(3); + assertThat(actual.get(0).getStartAt()).isEqualTo(LocalDate.of(2023, 7, 1)); } - @DisplayName("시작 적인 쿠폰들을 조회한다. - List") + @DisplayName("종료된 쿠폰들을 발급 가능 날짜 순으로 조회한다. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void couponSearchRepository_findAllByStatus_notStarted(List coupons) { + void findAllByStatus_ended_order_by_startAt(List coupons) { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(false, true, false); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); + CouponStatusRequest request = CouponFixture.couponStatusRequest(false, true); + LocalDate now = LocalDate.of(2023, 8, 1); couponRepository.saveAll(coupons); @@ -127,39 +96,6 @@ void couponSearchRepository_findAllByStatus_notStarted(List coupons) { // Then assertThat(actual).hasSize(5); - } - - @DisplayName("종료된 쿠폰들을 조회한다. - List") - @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") - @ParameterizedTest - void couponSearchRepository_findAllByStatus_ended(List coupons) { - // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false, true); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); - - couponRepository.saveAll(coupons); - - // When - List actual = couponSearchRepository.findAllByStatus(now, request); - - // Then - assertThat(actual).hasSize(2); - } - - @DisplayName("상태조건을 걸지 않아서 모든 쿠폰이 조회되지 않는다. - List") - @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") - @ParameterizedTest - void couponSearchRepository_findAllByStatus__not_status(List coupons) { - // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false, false); - LocalDateTime now = LocalDateTime.of(2023, 5, 1, 0, 0); - - couponRepository.saveAll(coupons); - - // When - List actual = couponSearchRepository.findAllByStatus(now, request); - - // Then - assertThat(actual).isEmpty(); + assertThat(actual.get(0).getStartAt()).isEqualTo(LocalDate.of(2023, 3, 1)); } } diff --git a/src/test/java/com/moabam/api/dto/coupon/CreateCouponRequestTest.java b/src/test/java/com/moabam/api/dto/coupon/CreateCouponRequestTest.java index a3fb6433..5fcf7561 100644 --- a/src/test/java/com/moabam/api/dto/coupon/CreateCouponRequestTest.java +++ b/src/test/java/com/moabam/api/dto/coupon/CreateCouponRequestTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.*; -import java.time.LocalDateTime; +import java.time.LocalDate; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,19 +13,19 @@ class CreateCouponRequestTest { - @DisplayName("쿠폰 발급 가능 시작 날짜가 올바른 형식으로 입력된다. - yyyy-MM-dd'T'HH:mm") + @DisplayName("쿠폰 발급 가능 시작 날짜가 올바른 형식으로 입력된다. - yyyy-MM-dd") @Test void createCouponRequest_StartAt() throws JsonProcessingException { // Given ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); - String json = "{\"startAt\":\"2023-11-09T10:10\"}"; + String json = "{\"startAt\":\"2023-11-09\"}"; // When CreateCouponRequest actual = objectMapper.readValue(json, CreateCouponRequest.class); // Then - assertThat(actual.startAt()).isEqualTo(LocalDateTime.of(2023, 11, 9, 10, 10)); + assertThat(actual.startAt()).isEqualTo(LocalDate.of(2023, 11, 9)); } } diff --git a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java index e239880c..87173012 100644 --- a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java +++ b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java @@ -63,8 +63,8 @@ class CouponControllerTest extends WithoutFilterSupporter { @Test void create_Coupon() throws Exception { // Given - String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); // When & Then mockMvc.perform(post("/admins/coupons") @@ -79,12 +79,38 @@ void create_Coupon() throws Exception { } @WithMember(role = Role.ADMIN) - @DisplayName("POST - 쿠폰 발급 종료기간 시작기간보다 이전인 쿠폰을 발행한다. - BadRequestException") + @DisplayName("POST - 현재 날짜가 쿠폰 발급 가능 날짜와 같거나 이후이다. - BadRequestException") + @Test + void create_Coupon_StartAt_BadRequestException() throws Exception { + // Given + CreateCouponRequest request = CouponFixture.createCouponRequest(); + + given(clockHolder.times()).willReturn(LocalDateTime.of(2025, 1, 1, 1, 1)); + + // When & Then + mockMvc.perform(post("/admins/coupons") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andDo(document("admins/coupons", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + CouponSnippetFixture.CREATE_COUPON_REQUEST, + ErrorSnippetFixture.ERROR_MESSAGE_RESPONSE)) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_COUPON_START_AT_PERIOD.getMessage())); + } + + @WithMember(role = Role.ADMIN) + @DisplayName("POST - 쿠폰 정보 오픈 날짜가 쿠폰 발급 시작 날짜와 같거나 이후인 쿠폰을 발행한다. - BadRequestException") @Test - void create_Coupon_BadRequestException() throws Exception { + void create_Coupon_OpenAt_BadRequestException() throws Exception { // Given String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 2, 1); + CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 1); + + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); // When & Then mockMvc.perform(post("/admins/coupons") @@ -98,7 +124,7 @@ void create_Coupon_BadRequestException() throws Exception { ErrorSnippetFixture.ERROR_MESSAGE_RESPONSE)) .andExpect(status().isBadRequest()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_COUPON_PERIOD.getMessage())); + .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_COUPON_OPEN_AT_PERIOD.getMessage())); } @WithMember(role = Role.ADMIN) @@ -106,8 +132,7 @@ void create_Coupon_BadRequestException() throws Exception { @Test void create_Coupon_ConflictException() throws Exception { // Given - String couponType = CouponType.GOLDEN_COUPON.getName(); - CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2); + CreateCouponRequest request = CouponFixture.createCouponRequest(); couponRepository.save(CouponMapper.toEntity(1L, request)); // When & Then @@ -195,9 +220,11 @@ void getById_Coupon_NotFoundException() throws Exception { @ParameterizedTest void getAllByStatus_Coupons(List coupons) throws Exception { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true, true); + CouponStatusRequest request = CouponFixture.couponStatusRequest(true, true); List coupon = couponRepository.saveAll(coupons); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 1, 1, 1, 1)); + // When & Then mockMvc.perform(post("/coupons/search") .contentType(MediaType.APPLICATION_JSON) @@ -213,14 +240,16 @@ void getAllByStatus_Coupons(List coupons) throws Exception { .andExpect(jsonPath("$", hasSize(coupon.size()))); } - @DisplayName("POST - 상태 조건을 걸지 않아서 쿠폰이 조회되지 않는다. - List") + @DisplayName("POST - 발급 가능한 쿠폰만 조회한다.. - List") @MethodSource("com.moabam.support.fixture.CouponFixture#provideCoupons") @ParameterizedTest - void getAllByStatus_Coupons_not_status(List coupons) throws Exception { + void getAllByStatus_Coupon(List coupons) throws Exception { // Given - CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false, false); + CouponStatusRequest request = CouponFixture.couponStatusRequest(false, false); couponRepository.saveAll(coupons); + given(clockHolder.times()).willReturn(LocalDateTime.of(2023, 3, 1, 1, 1)); + // When & Then mockMvc.perform(post("/coupons/search") .contentType(MediaType.APPLICATION_JSON) @@ -232,7 +261,7 @@ void getAllByStatus_Coupons_not_status(List coupons) throws Exception { CouponSnippetFixture.COUPON_STATUS_REQUEST)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$", hasSize(0))); + .andExpect(jsonPath("$", hasSize(1))); } @WithMember(nickname = "member-coupon-1") @@ -240,11 +269,10 @@ void getAllByStatus_Coupons_not_status(List coupons) throws Exception { @Test void registerQueue() throws Exception { // Given - Coupon couponFixture = CouponFixture.coupon("CouponName", 1, 2); - LocalDateTime now = LocalDateTime.of(2023, 1, 1, 1, 1); + Coupon couponFixture = CouponFixture.coupon(); Coupon coupon = couponRepository.save(couponFixture); - given(clockHolder.times()).willReturn(now); + given(clockHolder.times()).willReturn(LocalDateTime.of(2023, 2, 1, 1, 1)); // When & Then mockMvc.perform(post("/coupons") @@ -261,11 +289,10 @@ void registerQueue() throws Exception { @Test void registerQueue_BadRequestException() throws Exception { // Given - Coupon couponFixture = CouponFixture.coupon("CouponName", 1, 2); - LocalDateTime now = LocalDateTime.of(2022, 1, 1, 1, 1); + Coupon couponFixture = CouponFixture.coupon(); Coupon coupon = couponRepository.save(couponFixture); - given(clockHolder.times()).willReturn(now); + given(clockHolder.times()).willReturn(LocalDateTime.of(2022, 2, 1, 1, 1)); // When & Then mockMvc.perform(post("/coupons") @@ -277,7 +304,7 @@ void registerQueue_BadRequestException() throws Exception { ErrorSnippetFixture.ERROR_MESSAGE_RESPONSE)) .andExpect(status().isBadRequest()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_COUPON_PERIOD_END.getMessage())); + .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_COUPON_PERIOD.getMessage())); } @WithMember @@ -285,10 +312,9 @@ void registerQueue_BadRequestException() throws Exception { @Test void registerQueue_NotFoundException() throws Exception { // Given - Coupon coupon = CouponFixture.coupon("Not found coupon name", 1, 2); - LocalDateTime now = LocalDateTime.of(2023, 1, 1, 1, 1); + Coupon coupon = CouponFixture.coupon("Not found coupon name", 2, 1); - given(clockHolder.times()).willReturn(now); + given(clockHolder.times()).willReturn(LocalDateTime.of(2023, 2, 1, 1, 1)); // When & Then mockMvc.perform(post("/coupons") diff --git a/src/test/java/com/moabam/support/fixture/CouponFixture.java b/src/test/java/com/moabam/support/fixture/CouponFixture.java index 09ff443a..af514fb9 100644 --- a/src/test/java/com/moabam/support/fixture/CouponFixture.java +++ b/src/test/java/com/moabam/support/fixture/CouponFixture.java @@ -1,6 +1,6 @@ package com.moabam.support.fixture; -import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.List; import java.util.stream.Stream; @@ -16,26 +16,38 @@ public final class CouponFixture { public static final String DISCOUNT_1000_COUPON_NAME = "황금벌레 1000원 할인"; public static final String DISCOUNT_10000_COUPON_NAME = "황금벌레 10000원 할인"; + public static Coupon coupon() { + return Coupon.builder() + .name("couponName") + .point(1000) + .type(CouponType.MORNING_COUPON) + .stock(100) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 1, 1)) + .adminId(1L) + .build(); + } + public static Coupon coupon(int point, int stock) { return Coupon.builder() .name("couponName") .point(point) .type(CouponType.MORNING_COUPON) .stock(stock) - .startAt(LocalDateTime.of(2023, 1, 1, 0, 0)) - .endAt(LocalDateTime.of(2023, 2, 1, 0, 0)) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 1, 1)) .adminId(1L) .build(); } - public static Coupon coupon(String name, int startMonth, int endMonth) { + public static Coupon coupon(String name, int startMonth, int openMonth) { return Coupon.builder() .name(name) .point(10) .type(CouponType.MORNING_COUPON) .stock(100) - .startAt(LocalDateTime.of(2023, startMonth, 1, 0, 0)) - .endAt(LocalDateTime.of(2023, endMonth, 1, 0, 0)) + .startAt(LocalDate.of(2023, startMonth, 1)) + .openAt(LocalDate.of(2023, openMonth, 1)) .adminId(1L) .build(); } @@ -46,8 +58,8 @@ public static Coupon discount1000Coupon() { .point(1000) .type(CouponType.DISCOUNT_COUPON) .stock(100) - .startAt(LocalDateTime.of(2023, 1, 1, 0, 0)) - .endAt(LocalDateTime.of(2023, 1, 1, 0, 0)) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 1, 1)) .adminId(1L) .build(); } @@ -58,28 +70,39 @@ public static Coupon discount10000Coupon() { .point(10000) .type(CouponType.DISCOUNT_COUPON) .stock(100) - .startAt(LocalDateTime.of(2023, 1, 1, 0, 0)) - .endAt(LocalDateTime.of(2023, 1, 1, 0, 0)) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 2, 1)) .adminId(1L) .build(); } - public static CreateCouponRequest createCouponRequest(String couponType, int startMonth, int endMonth) { + public static CreateCouponRequest createCouponRequest() { + return CreateCouponRequest.builder() + .name("couponName") + .description("coupon description") + .point(10) + .type(CouponType.GOLDEN_COUPON.getName()) + .stock(10) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 1, 1)) + .build(); + } + + public static CreateCouponRequest createCouponRequest(String couponType, int startMonth, int openMonth) { return CreateCouponRequest.builder() .name("couponName") .description("coupon description") .point(10) .type(couponType) .stock(10) - .startAt(LocalDateTime.of(2023, startMonth, 1, 0, 0)) - .endAt(LocalDateTime.of(2023, endMonth, 1, 0, 0)) + .startAt(LocalDate.of(2023, startMonth, 1)) + .openAt(LocalDate.of(2023, openMonth, 1)) .build(); } - public static CouponStatusRequest couponStatusRequest(boolean ongoing, boolean notStarted, boolean ended) { + public static CouponStatusRequest couponStatusRequest(boolean ongoing, boolean ended) { return CouponStatusRequest.builder() - .ongoing(ongoing) - .notStarted(notStarted) + .opened(ongoing) .ended(ended) .build(); } @@ -87,16 +110,16 @@ public static CouponStatusRequest couponStatusRequest(boolean ongoing, boolean n public static Stream provideCoupons() { return Stream.of(Arguments.of( List.of( - coupon("coupon1", 1, 3), - coupon("coupon2", 2, 4), - coupon("coupon3", 3, 5), - coupon("coupon4", 4, 6), - coupon("coupon5", 5, 7), - coupon("coupon6", 6, 8), - coupon("coupon7", 7, 9), - coupon("coupon8", 8, 10), - coupon("coupon9", 9, 11), - coupon("coupon10", 10, 12) + coupon("coupon1", 3, 1), + coupon("coupon2", 4, 2), + coupon("coupon3", 5, 3), + coupon("coupon4", 6, 4), + coupon("coupon5", 7, 5), + coupon("coupon6", 8, 6), + coupon("coupon7", 9, 7), + coupon("coupon8", 10, 8), + coupon("coupon9", 11, 9), + coupon("coupon10", 12, 10) )) ); } diff --git a/src/test/java/com/moabam/support/fixture/CouponSnippetFixture.java b/src/test/java/com/moabam/support/fixture/CouponSnippetFixture.java index 57b7499e..40c7c63a 100644 --- a/src/test/java/com/moabam/support/fixture/CouponSnippetFixture.java +++ b/src/test/java/com/moabam/support/fixture/CouponSnippetFixture.java @@ -15,8 +15,8 @@ public final class CouponSnippetFixture { fieldWithPath("type").type(STRING).description("쿠폰 종류 (아침, 저녁, 황금, 할인)"), fieldWithPath("point").type(NUMBER).description("쿠폰 사용 시, 제공하는 포인트량"), fieldWithPath("stock").type(NUMBER).description("쿠폰을 발급 받을 수 있는 수"), - fieldWithPath("startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd'T'HH:mm)"), - fieldWithPath("endAt").type(STRING).description("쿠폰 발급 종료 날짜 (Ex: yyyy-MM-dd'T'HH:mm)") + fieldWithPath("startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd)"), + fieldWithPath("openAt").type(STRING).description("쿠폰 정보 오픈 날짜 (Ex: yyyy-MM-dd)") ); public static final ResponseFieldsSnippet COUPON_RESPONSE = responseFields( @@ -28,14 +28,13 @@ public final class CouponSnippetFixture { fieldWithPath("stock").type(NUMBER).description("쿠폰을 발급 받을 수 있는 수"), fieldWithPath("type").type(STRING) .description("쿠폰 종류 (MORNING_COUPON, NIGHT_COUPON, GOLDEN_COUPON, DISCOUNT_COUPON)"), - fieldWithPath("startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd'T'HH:mm)"), - fieldWithPath("endAt").type(STRING).description("쿠폰 발급 종료 날짜 (Ex: yyyy-MM-dd'T'HH:mm)") + fieldWithPath("startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd)"), + fieldWithPath("openAt").type(STRING).description("쿠폰 정보 오픈 날짜 (Ex: yyyy-MM-dd)") ); public static final Snippet COUPON_STATUS_REQUEST = requestFields( - fieldWithPath("ongoing").type(BOOLEAN).description("진행 상태 쿠폰 (true, false)"), - fieldWithPath("notStarted").type(BOOLEAN).description("시작전 상태 쿠폰 (true, false)"), - fieldWithPath("ended").type(BOOLEAN).description("종료 상태 쿠폰 (true, false)") + fieldWithPath("opened").type(BOOLEAN).description("쿠폰 정보가 오픈된 쿠폰 (true, false)"), + fieldWithPath("ended").type(BOOLEAN).description("종료된 쿠폰 (true, false)") ); public static final ResponseFieldsSnippet COUPON_STATUS_RESPONSE = responseFields( @@ -47,7 +46,7 @@ public final class CouponSnippetFixture { fieldWithPath("[].stock").type(NUMBER).description("쿠폰을 발급 받을 수 있는 수"), fieldWithPath("[].type").type(STRING) .description("쿠폰 종류 (MORNING_COUPON, NIGHT_COUPON, GOLDEN_COUPON, DISCOUNT_COUPON)"), - fieldWithPath("[].startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd'T'HH:mm)"), - fieldWithPath("[].endAt").type(STRING).description("쿠폰 발급 종료 날짜 (Ex: yyyy-MM-dd'T'HH:mm)") + fieldWithPath("[].startAt").type(STRING).description("쿠폰 발급 시작 날짜 (Ex: yyyy-MM-dd)"), + fieldWithPath("[].openAt").type(STRING).description("쿠폰 정보 오픈 날짜 (Ex: yyyy-MM-dd)") ); }