diff --git a/src/main/java/store/ckin/coupon/coupon/controller/CouponController.java b/src/main/java/store/ckin/coupon/coupon/controller/CouponController.java index 61c32c5..471370d 100644 --- a/src/main/java/store/ckin/coupon/coupon/controller/CouponController.java +++ b/src/main/java/store/ckin/coupon/coupon/controller/CouponController.java @@ -10,7 +10,6 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Propagation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -54,10 +53,10 @@ public ResponseEntity createCoupon(@Valid @RequestBody CreateCouponRequest * @param memberId 회원 아이디 */ @PostMapping("/welcome") - public ResponseEntity createWelcomeCoupon(@RequestParam("memberId") Long memberId) { + public ResponseEntity createWelcomeCoupon(@RequestParam("memberId") Long memberId) { couponService.createWelcomeCoupon(memberId); - return ResponseEntity.status(HttpStatus.CREATED).build(); + return ResponseEntity.status(HttpStatus.CREATED).body(true); } /** @@ -70,7 +69,6 @@ public ResponseEntity createWelcomeCoupon(@RequestParam("memberId") Long m public ResponseEntity createCouponByIds(@PathVariable("memberId") Long memberId, @PathVariable("couponTemplateId") Long couponTemplateId) { boolean content = couponService.createCouponByIds(memberId, couponTemplateId); - log.debug("content: {}", content); return ResponseEntity.status(HttpStatus.CREATED).body(content); } @@ -179,8 +177,7 @@ public ResponseEntity updateCouponUsedDate(@RequestParam("couponId") List< */ @GetMapping("/sale") public ResponseEntity> getCouponForBuyList(@RequestParam("memberId") Long memberId, - @RequestParam("bookId") - List bookIdList) { + @RequestParam("bookId") List bookIdList) { List content = couponService.getCouponForBuyList(memberId, bookIdList); diff --git a/src/main/java/store/ckin/coupon/coupon/dto/request/CreateCouponRequestDto.java b/src/main/java/store/ckin/coupon/coupon/dto/request/CreateCouponRequestDto.java index 7615b81..af4d4fa 100644 --- a/src/main/java/store/ckin/coupon/coupon/dto/request/CreateCouponRequestDto.java +++ b/src/main/java/store/ckin/coupon/coupon/dto/request/CreateCouponRequestDto.java @@ -3,7 +3,6 @@ import java.util.Date; import javax.validation.constraints.NotNull; import javax.validation.constraints.PositiveOrZero; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -27,14 +26,4 @@ public class CreateCouponRequestDto { @NotNull(message = "쿠폰 발급일을 입력해주세요.") private Date issueDate; private Date usedDate; - - @Builder - public CreateCouponRequestDto(Long memberId, Long couponTemplateId, Date expirationDate, Date issueDate, - Date usedDate) { - this.memberId = memberId; - this.couponTemplateId = couponTemplateId; - this.expirationDate = expirationDate; - this.issueDate = issueDate; - this.usedDate = usedDate; - } } diff --git a/src/main/java/store/ckin/coupon/coupon/service/impl/CouponServiceImpl.java b/src/main/java/store/ckin/coupon/coupon/service/impl/CouponServiceImpl.java index f593016..8a84951 100644 --- a/src/main/java/store/ckin/coupon/coupon/service/impl/CouponServiceImpl.java +++ b/src/main/java/store/ckin/coupon/coupon/service/impl/CouponServiceImpl.java @@ -7,7 +7,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import store.ckin.coupon.coupon.adapter.CouponAdapter; import store.ckin.coupon.coupon.dto.request.CreateCouponRequestDto; @@ -183,8 +182,7 @@ public boolean createCouponByIds(Long memberId, Long couponTemplateId) { if (!couponTemplateRepository.existsById((couponTemplateId))) { return false; } - - if (isExistCoupon(memberId, couponTemplateId)) { + if (Boolean.TRUE.equals(isExistCoupon(memberId, couponTemplateId))) { return false; } couponRepository.save(Coupon.builder() @@ -209,7 +207,7 @@ public void createWelcomeCoupon(Long memberId) { couponRepository.save(Coupon.builder() .memberId(memberId) .couponTemplateId(couponTemplateResponseDto.getId()) - .expirationDate(couponTemplateResponseDto.getExpirationDate()) + .expirationDate(Date.valueOf(LocalDate.now().plusDays(30))) .issueDate(Date.valueOf(LocalDate.now())) .usedDate(null) .build()); diff --git a/src/main/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateController.java b/src/main/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateController.java index dded29b..a0ac403 100644 --- a/src/main/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateController.java +++ b/src/main/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateController.java @@ -2,7 +2,6 @@ import javax.validation.Valid; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; @@ -27,7 +26,6 @@ * @author : gaeun * @version : 2024. 02. 15 */ -@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/coupon/couponTemplate") @@ -88,18 +86,18 @@ public ResponseEntity deleteCouponTemplate(@PathVariable("couponTemplateId return ResponseEntity.ok().build(); } -// /** -// * 쿠폰 템플릿 사용여부를 변경하는 메서드 입니다. -// * -// * @param templateId 템플릿 아이디 -// * @param state 사용여부 -// * @return 200 OK -// */ -// @PutMapping("/{templateId}") -// public ResponseEntity updateTemplateStatus(@PathVariable("templateId") Long templateId, -// @RequestParam("state") Boolean state) { -// couponTemplateService.updateCouponTemplateStatus(templateId, state); -// -// return ResponseEntity.ok().build(); -// } + /** + * 쿠폰 템플릿 사용여부를 변경하는 메서드 입니다. + * + * @param templateId 템플릿 아이디 + * @param state 사용여부 + * @return 200 OK + */ + @PutMapping("/{templateId}") + public ResponseEntity updateTemplateStatus(@PathVariable("templateId") Long templateId, + @RequestParam("state") Boolean state) { + couponTemplateService.updateCouponTemplateStatus(templateId, state); + + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/store/ckin/coupon/coupontemplate/repository/impl/CouponTemplateRepositoryImpl.java b/src/main/java/store/ckin/coupon/coupontemplate/repository/impl/CouponTemplateRepositoryImpl.java index 0a465ce..60ce153 100644 --- a/src/main/java/store/ckin/coupon/coupontemplate/repository/impl/CouponTemplateRepositoryImpl.java +++ b/src/main/java/store/ckin/coupon/coupontemplate/repository/impl/CouponTemplateRepositoryImpl.java @@ -110,6 +110,8 @@ public Optional getCouponTemplate(Long couponTempl @Override public GetCouponTemplateResponseDto getCouponTemplateByTypeId(Long typeId) { return from(couponTemplate) + .leftJoin(couponPolicy) + .on(couponTemplate.policyId.eq(couponPolicy.id)) .select(new QGetCouponTemplateResponseDto( couponTemplate.id, couponTemplate.policyId, diff --git a/src/main/java/store/ckin/coupon/coupontemplate/service/impl/CouponTemplateServiceImpl.java b/src/main/java/store/ckin/coupon/coupontemplate/service/impl/CouponTemplateServiceImpl.java index 124015f..2d25679 100644 --- a/src/main/java/store/ckin/coupon/coupontemplate/service/impl/CouponTemplateServiceImpl.java +++ b/src/main/java/store/ckin/coupon/coupontemplate/service/impl/CouponTemplateServiceImpl.java @@ -108,7 +108,6 @@ public void updateCouponTemplateStatus(Long templateId, Boolean state) { CouponTemplate couponTemplate = couponTemplateRepository.findById(templateId) .orElseThrow(CouponTemplateNotFoundException::new); - log.debug("state : {}", state); couponTemplate.updateTemplateStatus(state); } } diff --git a/src/main/java/store/ckin/coupon/util/AdapterHeaderUtil.java b/src/main/java/store/ckin/coupon/util/AdapterHeaderUtil.java index b9e7ee0..8f923f7 100644 --- a/src/main/java/store/ckin/coupon/util/AdapterHeaderUtil.java +++ b/src/main/java/store/ckin/coupon/util/AdapterHeaderUtil.java @@ -1,16 +1,13 @@ package store.ckin.coupon.util; import java.util.List; -import javax.servlet.http.HttpServletRequest; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; /** * Adapter 에서 사용할 헤더를 만드는 클래스입니다. * - * @author 정승조 + * @author 이가은 * @version 2024. 02. 15. */ public class AdapterHeaderUtil { @@ -26,9 +23,6 @@ private AdapterHeaderUtil() { public static HttpHeaders getHttpHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); - HttpServletRequest request = ((ServletRequestAttributes) - RequestContextHolder.currentRequestAttributes()).getRequest(); - httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.setAccept(List.of(MediaType.APPLICATION_JSON)); diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index e69de29..f8ece8d 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -0,0 +1,2 @@ +# gateway URL +port.gateway-uri=http://133.186.209.180:9010 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1acceac..78e25c8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -26,5 +26,5 @@ ckin.keymanager.url=https://api-keymanager.nhncloudservice.com ckin.keymanager.path=/keymanager/v1.0/appkey/{appkey}/secrets/{keyid} # gateway URL -port.gateway-uri=http://localhost:9010 +port.gateway-uri=http://localhost:9010 diff --git a/src/test/java/store/ckin/coupon/coupon/controller/CouponControllerTest.java b/src/test/java/store/ckin/coupon/coupon/controller/CouponControllerTest.java index 50c9122..8f5f4d9 100644 --- a/src/test/java/store/ckin/coupon/coupon/controller/CouponControllerTest.java +++ b/src/test/java/store/ckin/coupon/coupon/controller/CouponControllerTest.java @@ -1,6 +1,29 @@ package store.ckin.coupon.coupon.controller; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Date; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -12,32 +35,13 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import store.ckin.coupon.coupon.dto.request.CreateCouponRequestDto; import store.ckin.coupon.coupon.dto.response.GetCouponResponseDto; import store.ckin.coupon.coupon.service.CouponService; -import java.sql.Date; -import java.util.List; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.when; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * description: * @@ -75,6 +79,11 @@ void setUp() { ReflectionTestUtils.setField(couponResponseDto, "memberId", 1L); ReflectionTestUtils.setField(couponResponseDto, "couponTemplateId", 1L); ReflectionTestUtils.setField(couponResponseDto, "policyId", 1L); + ReflectionTestUtils.setField(couponResponseDto, "couponCodeId", 1L); + ReflectionTestUtils.setField(couponResponseDto, "minOrderPrice", 10000); + ReflectionTestUtils.setField(couponResponseDto, "discountPrice", null); + ReflectionTestUtils.setField(couponResponseDto, "discountRate", 10); + ReflectionTestUtils.setField(couponResponseDto, "maxDiscountPrice", 20000); ReflectionTestUtils.setField(couponResponseDto, "bookId", 1L); ReflectionTestUtils.setField(couponResponseDto, "categoryId", null); ReflectionTestUtils.setField(couponResponseDto, "typeId", 2L); @@ -98,27 +107,55 @@ void testCreateCoupon() throws Exception { .content(objectMapper.writeValueAsString(couponRequestDto)) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) - .andDo(print()); -// .andDo(document("coupon/createCoupon/success", -// preprocessRequest(prettyPrint()), -// preprocessResponse(prettyPrint()), -// requestParameters( -// parameterWithName("page").description("지정할 페이지"), -// parameterWithName("size").description("한 페이지 당 표시할 개수") -// ), -// responseFields( -// -// -// ))); + .andDo(document("coupon/createCoupon/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수") + ), + requestFields( + fieldWithPath("memberId").description("쿠폰을 지급받을 회원 아이디"), + fieldWithPath("couponTemplateId").description("쿠폰을 찍어낼 쿠폰 템플릿 아이디"), + fieldWithPath("expirationDate").description("쿠폰 만료일"), + fieldWithPath("issueDate").description("쿠폰 발급일"), + fieldWithPath("usedDate").description("쿠폰 사용일") + ))); + } + + @Test + @DisplayName("Welcome 쿠폰 생성 테스트") + void testCreateWelcomeCoupon() throws Exception { + + mockMvc.perform(post("/coupon/welcome") + .param("memberId", objectMapper.writeValueAsString(1L)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andDo(document("coupon/createWelcomeCoupon/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("memberId").description("생일 쿠폰을 지급할 회원 아이디") + ))); } @Test @DisplayName("쿠폰 발급 기록을 확인하고 등록 테스트") void testCreateCouponByIds() throws Exception { + when(couponService.createCouponByIds(anyLong(), anyLong())).thenReturn(true); - mockMvc.perform(post("/coupon/members/{memberId}/{couponTemplateId}", 1L, 1L)) + mockMvc.perform(RestDocumentationRequestBuilders.post("/coupon/members/{memberId}/{couponTemplateId}", 1L, 1L)) .andExpect(status().isCreated()) - .andDo(print()); + .andDo(document("coupon/createCouponByIds/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("memberId").description("쿠폰을 발급받는 회원의 아이디"), + parameterWithName("couponTemplateId").description("지급할 쿠폰의 템플릿 번호") + ))); +// responseFields( +// fieldWithPath(".").description("쿠폰이 성공적으로 발급되었는지 여부") +// ))); } @Test @@ -136,6 +173,11 @@ void testGetAllCouponList() throws Exception { .andExpect(jsonPath("$.content[0].memberId", is(couponResponseDto.getPolicyId()), Long.class)) .andExpect(jsonPath("$.content[0].couponTemplateId", is(couponResponseDto.getPolicyId()), Long.class)) .andExpect(jsonPath("$.content[0].policyId", is(couponResponseDto.getPolicyId()), Long.class)) + .andExpect(jsonPath("$.content[0].couponCodeId", is(couponResponseDto.getCouponCodeId()), Long.class)) + .andExpect(jsonPath("$.content[0].minOrderPrice", is(couponResponseDto.getMinOrderPrice()), Integer.class)) + .andExpect(jsonPath("$.content[0].discountPrice", is(couponResponseDto.getDiscountPrice()), Integer.class)) + .andExpect(jsonPath("$.content[0].discountRate", is(couponResponseDto.getDiscountRate()), Integer.class)) + .andExpect(jsonPath("$.content[0].maxDiscountPrice", is(couponResponseDto.getMaxDiscountPrice()), Integer.class)) .andExpect(jsonPath("$.content[0].bookId", is(couponResponseDto.getBookId()), Long.class)) .andExpect(jsonPath("$.content[0].categoryId", is(couponResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].typeId", is(couponResponseDto.getTypeId()), Long.class)) @@ -143,7 +185,44 @@ void testGetAllCouponList() throws Exception { .andExpect(jsonPath("$.content[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.content[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.content[0].usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getAllCouponList/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수"), + parameterWithName("typeId").description("쿠폰 목록을 조회하기 위한 타입 아이디") + ), + responseFields( + fieldWithPath("content.[].id").description("쿠폰 아이디"), + fieldWithPath("content.[].memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("content.[].couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("content.[].policyId").description("쿠폰 정책 아이디"), + fieldWithPath("content.[].couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("content.[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("content.[].discountPrice").description("할인 금액"), + fieldWithPath("content.[].discountRate").description("할인율"), + fieldWithPath("content.[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("content.[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("content.[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("content.[].typeId").description("쿠폰 타입 아이디"), + fieldWithPath("content.[].name").description("쿠폰 이름"), + fieldWithPath("content.[].expirationDate").description("쿠폰 만료일"), + fieldWithPath("content.[].issueDate").description("쿠폰 발급일"), + fieldWithPath("content.[].usedDate").description("쿠폰 사용일"), + fieldWithPath("totalPages").description("총 페이지 수"), + fieldWithPath("number").description("현재 페이지 번호"), + fieldWithPath("pageable").description("페이지 정보"), + fieldWithPath("last").description("마지막 페이지인지 여부"), + fieldWithPath("totalElements").description("총 요소 개수"), + fieldWithPath("empty").description("요소가 비어있는지 여부"), + fieldWithPath("sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("size").description("총 요소 개수"), + fieldWithPath("first").description("페이지의 첫 번째 요소"), + fieldWithPath("numberOfElements").description("현재 페이지에 있는 요소의 수"), + fieldWithPath("sort.empty").description(" 정렬된 요소가 비어있는지 여부") + ))); } @Test @@ -164,10 +243,14 @@ void testGetAllCouponList_X() throws Exception { .andExpect(jsonPath("$.content[0].categoryId", is(couponResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].typeId", is(couponResponseDto.getTypeId()), Long.class)) .andExpect(jsonPath("$.content[0].name", equalTo(couponResponseDto.getName()))) - .andExpect(jsonPath("$.content[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) + .andExpect(jsonPath("$.content[0].expirationDate", + equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.content[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.content[0].usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getAllCouponList/miss-parameter-failed", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()) + )); } @Test @@ -175,7 +258,7 @@ void testGetAllCouponList_X() throws Exception { void testGetCouponByCouponId() throws Exception { when(couponService.getCouponByCouponId(anyLong())).thenReturn(couponResponseDto); - mockMvc.perform(get("/coupon/{couponId}", 1L) + mockMvc.perform(RestDocumentationRequestBuilders.get("/coupon/{couponId}", 1L) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(couponResponseDto.getId()), Long.class)) @@ -189,7 +272,30 @@ void testGetCouponByCouponId() throws Exception { .andExpect(jsonPath("$.expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getCouponByCouponId/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("couponId").description("쿠폰 아이디") + ), + responseFields( + fieldWithPath("id").description("쿠폰 아이디"), + fieldWithPath("memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("policyId").description("쿠폰 정책 아이디"), + fieldWithPath("couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("minOrderPrice").description("최소 주문 금액"), + fieldWithPath("discountPrice").description("할인 금액"), + fieldWithPath("discountRate").description("할인율"), + fieldWithPath("maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("typeId").description("쿠폰 타입 아이디"), + fieldWithPath("name").description("쿠폰 이름"), + fieldWithPath("expirationDate").description("쿠폰 만료일"), + fieldWithPath("issueDate").description("쿠폰 발급일"), + fieldWithPath("usedDate").description("쿠폰 사용일") + ))); } @Test @@ -197,7 +303,7 @@ void testGetCouponByCouponId() throws Exception { void testGetAllCouponByMember() throws Exception { when(couponService.getCouponByMember(any(), anyLong())).thenReturn(page); - mockMvc.perform(get("/coupon/members/{memberId}", 1L) + mockMvc.perform(RestDocumentationRequestBuilders.get("/coupon/members/{memberId}", 1L) .param("page", objectMapper.writeValueAsString(pageable.getPageNumber())) .param("size", objectMapper.writeValueAsString(pageable.getPageSize())) .contentType(MediaType.APPLICATION_JSON)) @@ -210,10 +316,50 @@ void testGetAllCouponByMember() throws Exception { .andExpect(jsonPath("$.content[0].categoryId", is(couponResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].typeId", is(couponResponseDto.getTypeId()), Long.class)) .andExpect(jsonPath("$.content[0].name", equalTo(couponResponseDto.getName()))) - .andExpect(jsonPath("$.content[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) + .andExpect(jsonPath("$.content[0].expirationDate", + equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.content[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.content[0].usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getAllCouponByMember/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수") + ), + pathParameters( + parameterWithName("memberId").description("회원 아이디") + ), + responseFields( + fieldWithPath("content.[].id").description("쿠폰 아이디"), + fieldWithPath("content.[].memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("content.[].couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("content.[].policyId").description("쿠폰 정책 아이디"), + fieldWithPath("content.[].couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("content.[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("content.[].discountPrice").description("할인 금액"), + fieldWithPath("content.[].discountRate").description("할인율"), + fieldWithPath("content.[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("content.[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("content.[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("content.[].typeId").description("쿠폰 타입 아이디"), + fieldWithPath("content.[].name").description("쿠폰 이름"), + fieldWithPath("content.[].expirationDate").description("쿠폰 만료일"), + fieldWithPath("content.[].issueDate").description("쿠폰 발급일"), + fieldWithPath("content.[].usedDate").description("쿠폰 사용일"), + fieldWithPath("pageable").description("페이지 정보"), + fieldWithPath("last").description("마지막 페이지인지 여부"), + fieldWithPath("totalElements").description("총 요소 개수"), + fieldWithPath("empty").description("요소가 비어있는지 여부"), + fieldWithPath("sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("size").description("총 요소 개수"), + fieldWithPath("first").description("페이지의 첫 번째 요소"), + fieldWithPath("numberOfElements").description("현재 페이지에 있는 요소의 수"), + fieldWithPath("sort.empty").description("정렬된 요소가 비어있는지 여부"), + fieldWithPath("totalPages").description("총 페이지 수"), + fieldWithPath("number").description("페이지의 번호") + ))); } @Test @@ -223,7 +369,7 @@ void testGetUsedCouponByMember() throws Exception { when(couponService.getUsedCouponByMember(any(), anyLong())).thenReturn(page); - mockMvc.perform(get("/coupon/members/used/{memberId}", 1L) + mockMvc.perform(RestDocumentationRequestBuilders.get("/coupon/members/used/{memberId}", 1L) .param("page", objectMapper.writeValueAsString(pageable.getPageNumber())) .param("size", objectMapper.writeValueAsString(pageable.getPageSize())) .contentType(MediaType.APPLICATION_JSON)) @@ -236,10 +382,50 @@ void testGetUsedCouponByMember() throws Exception { .andExpect(jsonPath("$.content[0].categoryId", is(couponResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].typeId", is(couponResponseDto.getTypeId()), Long.class)) .andExpect(jsonPath("$.content[0].name", equalTo(couponResponseDto.getName()))) - .andExpect(jsonPath("$.content[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) + .andExpect(jsonPath("$.content[0].expirationDate", + equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.content[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.content[0].usedDate", is(couponResponseDto.getUsedDate().toString()))) - .andDo(print()); + .andDo(document("coupon/getUsedCouponByMember/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수") + ), + pathParameters( + parameterWithName("memberId").description("회원 아이디") + ), + responseFields( + fieldWithPath("content.[].id").description("쿠폰 아이디"), + fieldWithPath("content.[].memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("content.[].couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("content.[].policyId").description("쿠폰 정책 아이디"), + fieldWithPath("content.[].couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("content.[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("content.[].discountPrice").description("할인 금액"), + fieldWithPath("content.[].discountRate").description("할인율"), + fieldWithPath("content.[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("content.[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("content.[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("content.[].typeId").description("쿠폰 타입 아이디"), + fieldWithPath("content.[].name").description("쿠폰 이름"), + fieldWithPath("content.[].expirationDate").description("쿠폰 만료일"), + fieldWithPath("content.[].issueDate").description("쿠폰 발급일"), + fieldWithPath("content.[].usedDate").description("쿠폰 사용일"), + fieldWithPath("pageable").description("페이지 정보"), + fieldWithPath("last").description("마지막 페이지인지 여부"), + fieldWithPath("totalElements").description("총 요소 개수"), + fieldWithPath("empty").description("요소가 비어있는지 여부"), + fieldWithPath("sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("size").description("총 요소 개수"), + fieldWithPath("first").description("페이지의 첫 번째 요소"), + fieldWithPath("numberOfElements").description("현재 페이지에 있는 요소의 수"), + fieldWithPath("sort.empty").description("정렬된 요소가 비어있는지 여부"), + fieldWithPath("totalPages").description("총 페이지 수"), + fieldWithPath("number").description("페이지의 번호") + ))); } @Test @@ -249,7 +435,7 @@ void testGetUnUsedCouponByMember() throws Exception { when(couponService.getUnUsedCouponByMember(any(), anyLong())).thenReturn(page); - mockMvc.perform(get("/coupon/members/unUsed/{memberId}", 1L) + mockMvc.perform(RestDocumentationRequestBuilders.get("/coupon/members/unUsed/{memberId}", 1L) .param("page", objectMapper.writeValueAsString(pageable.getPageNumber())) .param("size", objectMapper.writeValueAsString(pageable.getPageSize())) .contentType(MediaType.APPLICATION_JSON)) @@ -262,10 +448,50 @@ void testGetUnUsedCouponByMember() throws Exception { .andExpect(jsonPath("$.content[0].categoryId", is(couponResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].typeId", is(couponResponseDto.getTypeId()), Long.class)) .andExpect(jsonPath("$.content[0].name", equalTo(couponResponseDto.getName()))) - .andExpect(jsonPath("$.content[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) + .andExpect(jsonPath("$.content[0].expirationDate", + equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$.content[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$.content[0].usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getUnUsedCouponByMember/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수") + ), + pathParameters( + parameterWithName("memberId").description("회원 아이디") + ), + responseFields( + fieldWithPath("content.[].id").description("쿠폰 아이디"), + fieldWithPath("content.[].memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("content.[].couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("content.[].policyId").description("쿠폰 정책 아이디"), + fieldWithPath("content.[].couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("content.[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("content.[].discountPrice").description("할인 금액"), + fieldWithPath("content.[].discountRate").description("할인율"), + fieldWithPath("content.[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("content.[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("content.[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("content.[].typeId").description("쿠폰 타입 아이디"), + fieldWithPath("content.[].name").description("쿠폰 이름"), + fieldWithPath("content.[].expirationDate").description("쿠폰 만료일"), + fieldWithPath("content.[].issueDate").description("쿠폰 발급일"), + fieldWithPath("content.[].usedDate").description("쿠폰 사용일"), + fieldWithPath("pageable").description("페이지 정보"), + fieldWithPath("last").description("마지막 페이지인지 여부"), + fieldWithPath("totalElements").description("총 요소 개수"), + fieldWithPath("empty").description("요소가 비어있는지 여부"), + fieldWithPath("sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("size").description("총 요소 개수"), + fieldWithPath("first").description("페이지의 첫 번째 요소"), + fieldWithPath("numberOfElements").description("현재 페이지에 있는 요소의 수"), + fieldWithPath("sort.empty").description("정렬된 요소가 비어있는지 여부"), + fieldWithPath("totalPages").description("총 페이지 수"), + fieldWithPath("number").description("페이지의 번호") + ))); } @Test @@ -273,7 +499,12 @@ void testGetUnUsedCouponByMember() throws Exception { void testUpdateCouponUsedDate() throws Exception { mockMvc.perform(put("/coupon?couponId=1")) .andExpect(status().isOk()) - .andDo(print()); + .andDo(document("coupon/updateCouponUsedDate/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("couponId").description("사용한 쿠폰 목록") + ))); } @Test @@ -296,7 +527,32 @@ void testGetCouponForBuyList() throws Exception { .andExpect(jsonPath("$[0].expirationDate", equalTo(couponResponseDto.getExpirationDate().toString()))) .andExpect(jsonPath("$[0].issueDate", is(couponResponseDto.getIssueDate().toString()))) .andExpect(jsonPath("$[0].usedDate", is(couponResponseDto.getUsedDate()))) - .andDo(print()); + .andDo(document("coupon/getUnUsedCouponByMember/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("memberId").description("회원 아이디"), + parameterWithName("bookId").description("도서 아이디 목록") + ), + responseFields( + fieldWithPath("[].id").description("쿠폰 아이디"), + fieldWithPath("[].memberId").description("쿠폰을 지급받은 회원 아이디"), + fieldWithPath("[].couponTemplateId").description("쿠폰 템플릿 아이디"), + fieldWithPath("[].policyId").description("쿠폰 정책 아이디"), + fieldWithPath("[].couponCodeId").description("쿠폰 정책 코드 아이디"), + fieldWithPath("[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("[].discountPrice").description("할인 금액"), + fieldWithPath("[].discountRate").description("할인율"), + fieldWithPath("[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("[].typeId").description("쿠폰 타입 아이디"), + fieldWithPath("[].name").description("쿠폰 이름"), + fieldWithPath("[].expirationDate").description("쿠폰 만료일"), + fieldWithPath("[].issueDate").description("쿠폰 발급일"), + fieldWithPath("[].usedDate").description("쿠폰 사용일") + ))); + } } diff --git a/src/test/java/store/ckin/coupon/coupon/service/CouponServiceTest.java b/src/test/java/store/ckin/coupon/coupon/service/CouponServiceTest.java index fb6f8c9..2340b51 100644 --- a/src/test/java/store/ckin/coupon/coupon/service/CouponServiceTest.java +++ b/src/test/java/store/ckin/coupon/coupon/service/CouponServiceTest.java @@ -1,6 +1,7 @@ package store.ckin.coupon.coupon.service; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,6 +20,8 @@ import store.ckin.coupon.coupon.model.Coupon; import store.ckin.coupon.coupon.repository.CouponRepository; import store.ckin.coupon.coupon.service.impl.CouponServiceImpl; +import store.ckin.coupon.coupontemplate.dto.request.CreateCouponTemplateRequestDto; +import store.ckin.coupon.coupontemplate.dto.response.GetCouponTemplateResponseDto; import store.ckin.coupon.coupontemplate.exception.CouponTemplateTypeNotFoundException; import store.ckin.coupon.coupontemplate.model.CouponTemplate; import store.ckin.coupon.coupontemplate.model.CouponTemplateType; @@ -68,6 +71,8 @@ class CouponServiceTest { Pageable pageable; PageImpl page; List couponList; + GetCouponTemplateResponseDto couponTemplateResponseDto; + CreateCouponTemplateRequestDto couponTemplateRequestDto; @BeforeEach void setUp() { @@ -99,6 +104,22 @@ void setUp() { ReflectionTestUtils.setField(couponResponseDto, "issueDate", Date.valueOf("2024-02-28")); ReflectionTestUtils.setField(couponResponseDto, "usedDate", null); + couponTemplateResponseDto = new GetCouponTemplateResponseDto(); + ReflectionTestUtils.setField(couponTemplateResponseDto, "id", 1L); + ReflectionTestUtils.setField(couponTemplateResponseDto, "policyId", 1L); + ReflectionTestUtils.setField(couponTemplateResponseDto, "minOrderPrice", 50000); + ReflectionTestUtils.setField(couponTemplateResponseDto, "discountPrice", 10000); + ReflectionTestUtils.setField(couponTemplateResponseDto, "discountRate", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "maxDiscountPrice", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "bookId", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "categoryId", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "name", "Welcome 쿠폰"); + ReflectionTestUtils.setField(couponTemplateResponseDto, "amount", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "typeId", 1L); + ReflectionTestUtils.setField(couponTemplateResponseDto, "duration", 30); + ReflectionTestUtils.setField(couponTemplateResponseDto, "expirationDate", null); + ReflectionTestUtils.setField(couponTemplateResponseDto, "state", true); + pageable = PageRequest.of(0, 5); page = new PageImpl<>(List.of(couponResponseDto)); @@ -127,6 +148,14 @@ void testCreateCoupon() { .save(any()); } + @Test + @DisplayName("쿠폰 생성 테스트 : 템플릿 타입이 없는 경우") + void testCreateCoupon_X() { + when(couponTemplateTypeRepository.existsById(anyLong())).thenReturn(false); + + Assertions.assertThrows(CouponTemplateTypeNotFoundException.class, () -> couponService.createCoupon(couponRequestDto)); + } + @Test @DisplayName("쿠폰 조회 테스트 : 회원의 사용완료된 쿠폰") void testGetUsedCouponByMember() { @@ -287,4 +316,16 @@ void testCreateCouponByIds_XC() { verify(couponRepository, times(1)) .isExistCoupon(anyLong(), anyLong()); } + @Test + @DisplayName("웰컴 쿠폰 생성 테스트") + void testCreateWelcomeCoupon() { + when(couponTemplateRepository.getCouponTemplateByTypeId(anyLong())).thenReturn(couponTemplateResponseDto); + + couponService.createWelcomeCoupon(1L); + + verify(couponTemplateRepository, times(1)) + .getCouponTemplateByTypeId(anyLong()); + verify(couponRepository, times(1)) + .save(any()); + } } \ No newline at end of file diff --git a/src/test/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateControllerTest.java b/src/test/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateControllerTest.java index 1be72f9..c6d754c 100644 --- a/src/test/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateControllerTest.java +++ b/src/test/java/store/ckin/coupon/coupontemplate/controller/CouponTemplateControllerTest.java @@ -1,41 +1,53 @@ package store.ckin.coupon.coupontemplate.controller; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; import java.sql.Date; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import store.ckin.coupon.coupontemplate.dto.request.CreateCouponTemplateRequestDto; import store.ckin.coupon.coupontemplate.dto.response.GetCouponTemplateResponseDto; import store.ckin.coupon.coupontemplate.service.CouponTemplateService; -import java.util.List; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** - * description: + * 쿠폰 템플릿 컨트롤러 테스트 입니다. * * @author : gaeun * @version : 2024. 02. 16 */ +@AutoConfigureRestDocs @WebMvcTest(CouponTemplateController.class) class CouponTemplateControllerTest { @Autowired @@ -54,8 +66,10 @@ void setUp() { objectMapper = new ObjectMapper(); typeId = 1L; couponTemplateRequestDto = new CreateCouponTemplateRequestDto(); - couponTemplateResponseDto = new GetCouponTemplateResponseDto(1L, 1L, 3000, 3000, 10000, null, 1L, null, "사람은 무엇으로 사는가 - 도서 쿠폰", 100L, 2L, 30, - Date.valueOf("2023-03-04"), true); + couponTemplateResponseDto = + new GetCouponTemplateResponseDto(1L, 1L, 3000, 3000, 10000, null, 1L, null, "사람은 무엇으로 사는가 - 도서 쿠폰", + 100L, 2L, 30, + Date.valueOf("2023-03-04"), true); } @Test @@ -76,10 +90,54 @@ void getAllCouponTemplateTest() throws Exception { .andExpect(jsonPath("$.content[0].id", is(couponTemplateResponseDto.getId()), Long.class)) .andExpect(jsonPath("$.content[0].policyId", is(couponTemplateResponseDto.getPolicyId()), Long.class)) .andExpect(jsonPath("$.content[0].bookId", is(couponTemplateResponseDto.getBookId()), Long.class)) - .andExpect(jsonPath("$.content[0].categoryId", is(couponTemplateResponseDto.getCategoryId()), Long.class)) + .andExpect( + jsonPath("$.content[0].categoryId", is(couponTemplateResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.content[0].name", equalTo(couponTemplateResponseDto.getName()))) .andExpect(jsonPath("$.content[0].amount", is(couponTemplateResponseDto.getAmount()), Long.class)) - .andDo(print()); + .andDo(document("couponTemplate/getAllCouponTemplate/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestParameters( + parameterWithName("page").description("지정할 페이지"), + parameterWithName("size").description("한 페이지 당 표시할 개수"), + parameterWithName("type").description("템플릿을 조회하기 위한 타입 아이디") + ), + responseFields( + fieldWithPath("content.[].state").description("쿠폰 템플릿 상태"), + fieldWithPath("content.[].id").description("쿠폰 템플릿 아이디"), + fieldWithPath("content.[].policyId").description("쿠폰 템플릿에 적용된 정책 아이디"), + fieldWithPath("content.[].minOrderPrice").description("최소 주문 금액"), + fieldWithPath("content.[].discountPrice").description("할인 금액"), + fieldWithPath("content.[].discountRate").description("할인율"), + fieldWithPath("content.[].maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("content.[].bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("content.[].categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("content.[].name").description("쿠폰 템플릿 이름"), + fieldWithPath("content.[].amount").description("쿠폰 템플릿 수량"), + fieldWithPath("content.[].typeId").description("쿠폰 템플릿 타입 아이디"), + fieldWithPath("content.[].duration").description("쿠폰 템플릿 사용기한"), + fieldWithPath("content.[].expirationDate").description("쿠폰 템플릿 만료일"), + fieldWithPath("pageable").description("페이지 관련 정보"), + fieldWithPath("number").description("현재 페이지 번호"), + fieldWithPath("pageable.offset").description("페이지의 시작 오프셋"), + fieldWithPath("pageable.pageNumber").description("현재 페이지가 마지막 페이지인지 여부"), + fieldWithPath("pageable.pageSize").description("페이지당 요소 개수"), + fieldWithPath("pageable.paged").description("페이징된 결과인지 여부"), + fieldWithPath("pageable.unpaged").description("페이징되지 않은 결과인지 여부"), + fieldWithPath("pageable.sort.empty").description("정렬된 요소가 비어있는지 여부"), + fieldWithPath("pageable.sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("pageable.sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("last").description("현재 페이지가 마지막 페이지인지 여부"), + fieldWithPath("totalElements").description("전체 요소 개수"), + fieldWithPath("totalPages").description("전체 페이지 수"), + fieldWithPath("sort.empty").description("정렬된 요소가 비어있는지 여부"), + fieldWithPath("sort.unsorted").description("정렬되지 않은 요소가 있는지 여부"), + fieldWithPath("sort.sorted").description("정렬된 요소가 있는지 여부"), + fieldWithPath("first").description("현재 페이지의 첫 번째 요소 여부"), + fieldWithPath("size").description("현재 페이지의 요소 개수"), + fieldWithPath("numberOfElements").description("현재 페이지의 요소 개수"), + fieldWithPath("empty").description("현재 페이지의 요소가 비어있는지 여부") + ))); } @Test @@ -87,7 +145,7 @@ void getAllCouponTemplateTest() throws Exception { void getCouponTemplateByIdTest() throws Exception { when(couponTemplateService.getCouponTemplate(anyLong())).thenReturn(couponTemplateResponseDto); - mockMvc.perform(get("/coupon/couponTemplate/{couponTemplateId}", 1L)) + mockMvc.perform(RestDocumentationRequestBuilders.get("/coupon/couponTemplate/{couponTemplateId}", 1L)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id", is(couponTemplateResponseDto.getId()), Long.class)) .andExpect(jsonPath("$.policyId", is(couponTemplateResponseDto.getPolicyId()), Long.class)) @@ -95,7 +153,28 @@ void getCouponTemplateByIdTest() throws Exception { .andExpect(jsonPath("$.categoryId", is(couponTemplateResponseDto.getCategoryId()), Long.class)) .andExpect(jsonPath("$.name", equalTo(couponTemplateResponseDto.getName()))) .andExpect(jsonPath("$.amount", is(couponTemplateResponseDto.getAmount()), Long.class)) - .andDo(print()); + .andDo(document("couponTemplate/getCouponTemplateById/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("couponTemplateId").description("조회할 쿠폰 템플릿의 아이디") + ), + responseFields( + fieldWithPath("state").description("쿠폰 템플릿 상태"), + fieldWithPath("id").description("쿠폰 템플릿 아이디"), + fieldWithPath("policyId").description("쿠폰 템플릿에 적용된 정책 아이디"), + fieldWithPath("minOrderPrice").description("최소 주문 금액"), + fieldWithPath("discountPrice").description("할인 금액"), + fieldWithPath("discountRate").description("할인율"), + fieldWithPath("maxDiscountPrice").description("최대 할인 금액"), + fieldWithPath("bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("name").description("쿠폰 템플릿 이름"), + fieldWithPath("amount").description("쿠폰 템플릿 수량"), + fieldWithPath("typeId").description("쿠폰 템플릿 타입 아이디"), + fieldWithPath("duration").description("쿠폰 템플릿 사용기한"), + fieldWithPath("expirationDate").description("쿠폰 템플릿 만료일") + ))); } @Test @@ -107,12 +186,28 @@ void createCouponTemplateTest() throws Exception { ReflectionTestUtils.setField(couponTemplateRequestDto, "typeId", 1L); ReflectionTestUtils.setField(couponTemplateRequestDto, "name", "해리포터 전집"); ReflectionTestUtils.setField(couponTemplateRequestDto, "amount", 100L); + ReflectionTestUtils.setField(couponTemplateRequestDto, "duration", 30); + ReflectionTestUtils.setField(couponTemplateRequestDto, "expirationDate", null); + ReflectionTestUtils.setField(couponTemplateRequestDto, "state", true); - mockMvc.perform(post("/coupon/couponTemplate") + mockMvc.perform(RestDocumentationRequestBuilders.post("/coupon/couponTemplate") .content(objectMapper.writeValueAsString(couponTemplateRequestDto)) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) - .andDo(print()); + .andDo(document("couponTemplate/createCouponTemplate/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("state").description("쿠폰 템플릿 상태"), + fieldWithPath("policyId").description("쿠폰 템플릿에 적용된 정책 아이디"), + fieldWithPath("bookId").description("쿠폰을 적용 가능한 도서 아이디"), + fieldWithPath("categoryId").description("쿠폰을 적용 가능한 카테고리 아이디"), + fieldWithPath("name").description("쿠폰 템플릿 이름"), + fieldWithPath("amount").description("쿠폰 템플릿 수량"), + fieldWithPath("typeId").description("쿠폰 템플릿 타입 아이디"), + fieldWithPath("duration").description("쿠폰 템플릿 사용기한"), + fieldWithPath("expirationDate").description("쿠폰 템플릿 만료일") + ))); } @Test @@ -123,45 +218,41 @@ void createCouponTemplateTest_X() throws Exception { .content(objectMapper.writeValueAsString(couponTemplateRequestDto)) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is4xxClientError()) - .andDo(print()); + .andDo(document("couponTemplate/createCouponTemplate/miss-parameter-failed", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()) + )); } -// @Test -// @DisplayName("쿠폰 템플릿 수정 테스트: 성공") -// void updateCouponTemplateTest() throws Exception { -// ReflectionTestUtils.setField(couponTemplateRequestDto, "policyId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "bookId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "categoryId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "typeId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "name", "해리포터 전집"); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "amount", 100L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "state", null); -// -// mockMvc.perform(put("/coupon/couponTemplate/{couponTemplateId}", 1L) -// .content(objectMapper.writeValueAsString(couponTemplateRequestDto)) -// .contentType(MediaType.APPLICATION_JSON)) -// .andExpect(status().isOk()) -// .andDo(print()); -// } -// -// @Test -// @DisplayName("쿠폰 템플릿 수정 테스트: 실패") -// void updateCouponTemplateTest_X() throws Exception { -// -// mockMvc.perform(put("/coupon/couponTemplate/{couponTemplateId}", 1L) -// .content(objectMapper.writeValueAsString(couponTemplateRequestDto)) -// .contentType(MediaType.APPLICATION_JSON)) -// .andExpect(status().is4xxClientError()) -// .andDo(print()); -// } - @Test @DisplayName("쿠폰 템플릿 삭제 테스트") void deleteCouponTemplateTest() throws Exception { - mockMvc.perform(delete("/coupon/couponTemplate/{couponTemplateId}", 1L)) + mockMvc.perform(RestDocumentationRequestBuilders.delete("/coupon/couponTemplate/{couponTemplateId}", 1L)) .andExpect(status().isOk()) - .andDo(print()); + .andDo(document("couponTemplate/deleteCouponTemplate/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("couponTemplateId").description("삭제할 쿠폰 템플릿의 아이디") + ))); + } + + @Test + @DisplayName("쿠폰 템플릿 사용여부 변경 테스트") + void testUpdateTemplateStatus() throws Exception { + mockMvc.perform(RestDocumentationRequestBuilders.put("/coupon/couponTemplate/{templateId}", 1L) + .param("state", "true") + ).andExpect(status().isOk()) + .andDo(document("couponTemplate/updateTemplateStatus/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("templateId").description("수정할 쿠폰 템플릿의 아이디") + ), + requestParameters( + parameterWithName("state").description("수정할 쿠폰 템플릿의 상태") + ))); } diff --git a/src/test/java/store/ckin/coupon/coupontemplate/repository/CouponTemplateRepositoryTest.java b/src/test/java/store/ckin/coupon/coupontemplate/repository/CouponTemplateRepositoryTest.java index f05685a..40c2d4d 100644 --- a/src/test/java/store/ckin/coupon/coupontemplate/repository/CouponTemplateRepositoryTest.java +++ b/src/test/java/store/ckin/coupon/coupontemplate/repository/CouponTemplateRepositoryTest.java @@ -1,5 +1,8 @@ package store.ckin.coupon.coupontemplate.repository; +import java.sql.Date; +import java.util.Optional; +import javax.persistence.EntityManager; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -9,22 +12,19 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.transaction.annotation.Transactional; import store.ckin.coupon.coupontemplate.dto.response.GetCouponTemplateResponseDto; import store.ckin.coupon.coupontemplate.model.CouponTemplate; import store.ckin.coupon.coupontemplate.model.CouponTemplateType; - -import javax.persistence.EntityManager; -import java.util.Optional; +import store.ckin.coupon.policy.model.CouponCode; +import store.ckin.coupon.policy.model.CouponPolicy; /** - * description: + * 쿠폰 템플릿 레파지토리 테스트 입니다. * * @author : gaeun * @version : 2024. 02. 16 */ @DataJpaTest -@Transactional class CouponTemplateRepositoryTest { @Autowired CouponTemplateRepository couponTemplateRepository; @@ -38,27 +38,43 @@ class CouponTemplateRepositoryTest { CouponTemplateType birthType; CouponTemplateType bookType; CouponTemplateType categoryType; + CouponPolicy couponPolicy; + CouponCode couponCode; @BeforeEach void setUp() { - + entityManager + .createNativeQuery("ALTER TABLE CouponPolicy ALTER COLUMN couponpolicy_id RESTART WITH 1") + .executeUpdate(); birthType = new CouponTemplateType(1L, "생일 쿠폰"); bookType = new CouponTemplateType(2L, "도서 쿠폰"); categoryType = new CouponTemplateType(3L, "카테고리 쿠폰"); + couponCode = new CouponCode("정률"); + couponPolicy = CouponPolicy.builder() + .couponCode(couponCode) + .discountPrice(null) + .maxDiscountPrice(20000) + .minOrderPrice(10000) + .discountRate(10) + .state(true) + .build(); entityManager.persist(birthType); entityManager.persist(bookType); entityManager.persist(categoryType); - - entityManager.flush(); + entityManager.persist(couponCode); + entityManager.persist(couponPolicy); birthCouponTemplate = CouponTemplate.builder() .policyId(1L) - .bookId(null) .categoryId(null) .name("1월 생일 쿠폰") .amount(100L) .type(birthType) + .state(true) + .duration(null) + .amount(10L) + .expirationDate(Date.valueOf("2024-03-31")) .build(); couponTemplateRepository.save(birthCouponTemplate); @@ -69,6 +85,10 @@ void setUp() { .name("사람은 무엇으로 사는가 - 도서 쿠폰") .amount(100L) .type(bookType) + .state(true) + .amount(10L) + .duration(null) + .expirationDate(Date.valueOf("2024-03-31")) .build(); couponTemplateRepository.save(bookCouponTemplate); @@ -79,9 +99,12 @@ void setUp() { .name("소설 - 카테고리 쿠폰") .amount(100L) .type(categoryType) + .amount(10L) + .state(true) + .duration(null) + .expirationDate(Date.valueOf("2024-03-31")) .build(); - entityManager.flush(); couponTemplateRepository.save(categoryCouponTemplate); } @@ -89,13 +112,15 @@ void setUp() { @DisplayName("쿠폰 템플릿 목록 가져오기 테스트") void testGetCouponTemplateList() { Pageable pageable = PageRequest.of(0, 5); - Page results = couponTemplateRepository.getCouponTemplateList(pageable, birthType.getId()); + Page results = + couponTemplateRepository.getCouponTemplateList(pageable, birthType.getId()); Assertions.assertThat(results).isNotNull(); Assertions.assertThat(results.getContent().get(0).getId()).isNotNull(); Assertions.assertThat(results.getContent().get(0).getPolicyId()).isEqualTo(birthCouponTemplate.getPolicyId()); Assertions.assertThat(results.getContent().get(0).getBookId()).isEqualTo(birthCouponTemplate.getBookId()); - Assertions.assertThat(results.getContent().get(0).getCategoryId()).isEqualTo(birthCouponTemplate.getCategoryId()); + Assertions.assertThat(results.getContent().get(0).getCategoryId()) + .isEqualTo(birthCouponTemplate.getCategoryId()); Assertions.assertThat(results.getContent().get(0).getName()).isEqualTo(birthCouponTemplate.getName()); Assertions.assertThat(results.getContent().get(0).getAmount()).isEqualTo(birthCouponTemplate.getAmount()); } @@ -103,7 +128,8 @@ void testGetCouponTemplateList() { @Test @DisplayName("쿠폰 템플릿 가져오기 테스트") void testGetCouponTemplate() { - Optional results = couponTemplateRepository.getCouponTemplate(bookCouponTemplate.getId()); + Optional results = + couponTemplateRepository.getCouponTemplate(bookCouponTemplate.getId()); Assertions.assertThat(results).isNotNull(); Assertions.assertThat(results.get().getId()).isNotNull(); @@ -113,4 +139,25 @@ void testGetCouponTemplate() { Assertions.assertThat(results.get().getName()).isEqualTo(bookCouponTemplate.getName()); Assertions.assertThat(results.get().getAmount()).isEqualTo(bookCouponTemplate.getAmount()); } + + @Test + @DisplayName("단일 쿠폰 템플릿 조회 테스트: 생일쿠폰, 웰컴쿠폰") + void testGetCouponTemplateByTypeId() { + GetCouponTemplateResponseDto results = couponTemplateRepository.getCouponTemplateByTypeId(1L); + + Assertions.assertThat(results).isNotNull(); + Assertions.assertThat(results.getId()).isNotNull(); + Assertions.assertThat(results.getPolicyId()).isEqualTo(birthCouponTemplate.getPolicyId()); + Assertions.assertThat(results.getMinOrderPrice()).isEqualTo(couponPolicy.getMinOrderPrice()); + Assertions.assertThat(results.getDiscountPrice()).isEqualTo(couponPolicy.getDiscountPrice()); + Assertions.assertThat(results.getDiscountRate()).isEqualTo(couponPolicy.getDiscountRate()); + Assertions.assertThat(results.getMaxDiscountPrice()).isEqualTo(couponPolicy.getMaxDiscountPrice()); + Assertions.assertThat(results.getBookId()).isEqualTo(birthCouponTemplate.getBookId()); + Assertions.assertThat(results.getCategoryId()).isEqualTo(birthCouponTemplate.getCategoryId()); + Assertions.assertThat(results.getName()).isEqualTo(birthCouponTemplate.getName()); + Assertions.assertThat(results.getAmount()).isEqualTo(birthCouponTemplate.getAmount()); + Assertions.assertThat(results.getState()).isEqualTo(birthCouponTemplate.getState()); + Assertions.assertThat(results.getDuration()).isEqualTo(birthCouponTemplate.getDuration()); + Assertions.assertThat(results.getExpirationDate()).isEqualTo(birthCouponTemplate.getExpirationDate()); + } } \ No newline at end of file diff --git a/src/test/java/store/ckin/coupon/coupontemplate/service/CouponTemplateServiceTest.java b/src/test/java/store/ckin/coupon/coupontemplate/service/CouponTemplateServiceTest.java index 8b1b802..c372604 100644 --- a/src/test/java/store/ckin/coupon/coupontemplate/service/CouponTemplateServiceTest.java +++ b/src/test/java/store/ckin/coupon/coupontemplate/service/CouponTemplateServiceTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.sql.Date; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -179,59 +180,6 @@ void testGetCouponTemplate_X() { assertThrows(CouponTemplateNotFoundException.class, () -> couponTemplateService.getCouponTemplate(1L)); } -// @Test -// @DisplayName("쿠폰 템플릿 수정 테스트") -// void testUpdateCouponTemplate() { -// ReflectionTestUtils.setField(couponTemplateRequestDto, "policyId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "bookId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "categoryId", null); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "typeId", bookType.getId()); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "name", "사람은 무엇으로 사는가 - 도서 쿠폰"); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "amount", 100L); -// -// when(couponTemplateRepository.findById(anyLong())).thenReturn(Optional.ofNullable(bookCouponTemplate)); -// when(couponPolicyRepository.existsById(anyLong())).thenReturn(true); -// -// couponTemplateService.updateCouponTemplate(1L, couponTemplateRequestDto); -// -// verify(couponTemplateRepository, times(1)) -// .findById(anyLong()); -// verify(couponPolicyRepository, times(1)) -// .existsById(anyLong()); -// } -// -// -// @Test -// @DisplayName("쿠폰 템플릿 수정 테스트: 실패") -// void testUpdateCouponTemplate_X() { -// ReflectionTestUtils.setField(couponTemplateRequestDto, "policyId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "bookId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "categoryId", null); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "typeId", bookType.getId()); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "name", "사람은 무엇으로 사는가 - 도서 쿠폰"); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "amount", 100L); -// -// when(couponTemplateRepository.existsById(anyLong())).thenReturn(false); -// -// assertThrows(CouponTemplateNotFoundException.class, () -> couponTemplateService.updateCouponTemplate(1L, couponTemplateRequestDto)); -// } -// -// @Test -// @DisplayName("쿠폰 템플릿 수정 테스트: 실패 : 존재하지 않는 정책 아이디") -// void testUpdateCouponTemplate_XP() { -// ReflectionTestUtils.setField(couponTemplateRequestDto, "policyId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "bookId", 1L); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "categoryId", null); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "typeId", bookType.getId()); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "name", "사람은 무엇으로 사는가 - 도서 쿠폰"); -// ReflectionTestUtils.setField(couponTemplateRequestDto, "amount", 100L); -// -// when(couponTemplateRepository.findById(anyLong())).thenReturn(Optional.ofNullable(bookCouponTemplate)); -// when(couponPolicyRepository.existsById(anyLong())).thenReturn(false); -// -// assertThrows(CouponPolicyNotFoundException.class, () -> couponTemplateService.updateCouponTemplate(1L, couponTemplateRequestDto)); -// } - @Test @DisplayName("쿠폰 템플릿 삭제 테스트") void testDeleteCouponTemplate() { @@ -243,6 +191,25 @@ void testDeleteCouponTemplate() { .delete(any()); } + @Test + @DisplayName("쿠폰 템플릿 단일 조회") + void updateCouponTemplateStatus() { + when(couponTemplateRepository.findById(anyLong())).thenReturn(Optional.ofNullable(bookCouponTemplate)); + + couponTemplateService.updateCouponTemplateStatus(1L, true); + + verify(couponTemplateRepository, times(1)) + .findById(anyLong()); + } + + @Test + @DisplayName("쿠폰 템플릿 단일 조회: 실패") + void updateCouponTemplateStatus_X() { + when(couponTemplateRepository.findById(anyLong())).thenReturn(Optional.empty()); + + Assertions.assertThrows(CouponTemplateNotFoundException.class, () -> couponTemplateService.updateCouponTemplateStatus(1L, true)); + } + @Test @DisplayName("쿠폰 템플릿 삭제 테스트: 실패") void testDeleteCouponTemplate_X() {