From 45ff27a9aac34fdd1ee0a419b467bc23fa95693a Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Mon, 19 Feb 2024 17:23:45 +0900 Subject: [PATCH] =?UTF-8?q?Product=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=98?= =?UTF-8?q?=EC=98=80=EC=8A=B5=EB=8B=88=EB=8B=A4.=20Dto=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=A9=94=ED=84=B0=20=EB=B6=88=EC=9D=BC=EC=B9=98=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20TODO=EB=A1=9C=20=EC=9D=B4=ED=9B=84=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=ED=95=B4=EC=95=BC=20=ED=95=A0=20=ED=95=AD=EB=AA=A9?= =?UTF-8?q?=EC=9D=84=20=EC=A0=81=EC=96=B4=EB=91=90=EC=97=88=EC=8A=B5?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.=20(=EB=B8=8C=EB=9E=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-api/src/docs/asciidoc/product-api.adoc | 9 +- .../product/dto/ProductDetailDto.java | 29 +++- .../controller/ProductControllerTest.java | 160 +++++++++++------- 3 files changed, 127 insertions(+), 71 deletions(-) diff --git a/module-api/src/docs/asciidoc/product-api.adoc b/module-api/src/docs/asciidoc/product-api.adoc index 767fa9ae..6068f8a4 100644 --- a/module-api/src/docs/asciidoc/product-api.adoc +++ b/module-api/src/docs/asciidoc/product-api.adoc @@ -5,20 +5,18 @@ === <제품 목록 조회> ===== HTTP Request - -include::{snippets}/products-list/get-products-list/http-request.adoc[] +include::{snippets}/products/get-products/http-request.adoc[] ==== Response -include::{snippets}/products-list/get-products-list/response-fields.adoc[] +include::{snippets}/products/get-products/response-fields.adoc[] ===== HTTP Response 예시 -include::{snippets}/products-list/get-products-list/http-response.adoc[] +include::{snippets}/products/get-products/http-response.adoc[] === <제품 아이디로 제품 목록 조회> ===== HTTP Request - include::{snippets}/product-id/get-product-id/http-request.adoc[] ==== Response @@ -31,7 +29,6 @@ include::{snippets}/product-id/get-product-id//http-response.adoc[] === <제품 키워드로 제품 목록 조회> ===== HTTP Request - include::{snippets}/products-search/get-products-by-search/http-request.adoc[] ==== Response diff --git a/module-api/src/main/java/com/kernel360/product/dto/ProductDetailDto.java b/module-api/src/main/java/com/kernel360/product/dto/ProductDetailDto.java index 0136fcd3..d7f48dca 100644 --- a/module-api/src/main/java/com/kernel360/product/dto/ProductDetailDto.java +++ b/module-api/src/main/java/com/kernel360/product/dto/ProductDetailDto.java @@ -1,6 +1,10 @@ package com.kernel360.product.dto; import com.kernel360.product.entity.Product; +import jakarta.persistence.Column; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; import java.time.LocalDate; @@ -35,7 +39,12 @@ public record ProductDetailDto( String manufactureType, String manufactureMethod, String manufactureNation, - String violationInfo + String violationInfo, + LocalDate createdAt, + String createdBy, + LocalDate modifiedAt, + String modifiedBy + //TODO 브랜드 엔티티 ) { public static ProductDetailDto of( @@ -66,7 +75,11 @@ public static ProductDetailDto of( String manufactureType, String manufactureMethod, String manufactureNation, - String violationInfo + String violationInfo, + LocalDate createdAt, + String createdBy, + LocalDate modifiedAt, + String modifiedBy ) { return new ProductDetailDto( productNo, @@ -96,7 +109,11 @@ public static ProductDetailDto of( manufactureType, manufactureMethod, manufactureNation, - violationInfo + violationInfo, + createdAt, + createdBy, + modifiedAt, + modifiedBy ); } @@ -129,7 +146,11 @@ public static ProductDetailDto from(Product entity) { entity.getManufactureType(), entity.getManufactureMethod(), entity.getManufactureNation(), - entity.getViolationInfo() + entity.getViolationInfo(), + entity.getCreatedAt(), + entity.getCreatedBy(), + entity.getModifiedAt(), + entity.getModifiedBy() ); } } \ No newline at end of file diff --git a/module-api/src/test/java/com/kernel360/product/controller/ProductControllerTest.java b/module-api/src/test/java/com/kernel360/product/controller/ProductControllerTest.java index d10cba04..e8b6b793 100644 --- a/module-api/src/test/java/com/kernel360/product/controller/ProductControllerTest.java +++ b/module-api/src/test/java/com/kernel360/product/controller/ProductControllerTest.java @@ -8,6 +8,7 @@ import com.navercorp.fixturemonkey.FixtureMonkey; import com.navercorp.fixturemonkey.api.introspector.*; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc; import org.springframework.data.domain.Page; @@ -53,6 +54,7 @@ class ProductControllerTest extends ControllerTest { @Test void 제품목록요청_왔을때_200응답과_리스폰스가_잘반환되는지() throws Exception { + //todo 브랜드 // given List expectedDtos = fixtureMonkey.giveMeBuilder(Product.class) .setNotNull("productNo") @@ -62,7 +64,6 @@ class ProductControllerTest extends ControllerTest { .setNotNull("reportNumber") .setNotNull("safetyStatus") .setNotNull("viewCount") - .setNotNull("brand") .setNotNull("upperItem") .setNotNull("createdAt") .setNotNull("createdBy") @@ -79,12 +80,12 @@ class ProductControllerTest extends ControllerTest { .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.value", hasSize(5))) - .andDo(document("products-list/get-products-list", + .andDo(document("products/get-products", responseFields( fieldWithPath("status").description("상태 코드"), - fieldWithPath("message").description("응답 메세지"), - fieldWithPath("code").description("비지니스 코드"), - fieldWithPath("value").description("제품 리스트"), + fieldWithPath("message").description("응답 메시지"), + fieldWithPath("code").description("비즈니스 코드"), + subsectionWithPath("value").description("제품 목록"), fieldWithPath("value[].productNo").description("제품번호").optional(), fieldWithPath("value[].productName").description("제품명").optional(), fieldWithPath("value[].barcode").description("바코드").optional(), @@ -92,7 +93,6 @@ class ProductControllerTest extends ControllerTest { fieldWithPath("value[].reportNumber").description("보고 번호").optional(), fieldWithPath("value[].safetyStatus").description("안전 상태").optional(), fieldWithPath("value[].viewCount").description("조회수").optional(), - fieldWithPath("value[].brand").description("브랜드").optional(), fieldWithPath("value[].upperItem").description("상위 분류").optional(), fieldWithPath("value[].createdAt").description("생성 날짜").optional(), fieldWithPath("value[].createdBy").description("생성자").optional(), @@ -105,81 +105,119 @@ class ProductControllerTest extends ControllerTest { @Test - void 제품아이디로_제품조회요청이왔을때_200응답과_리스폰스가_잘반환되는지() throws Exception { + void 제품고유번호로_제품상세조회요청이왔을때_200응답과_리스폰스가_잘반환되는지() throws Exception { + //TODO 브랜드, 제조국, grade, reviewCnt // given Product mockProduct = fixtureMonkey.giveMeBuilder(Product.class) .set("productNo", 1L) // Assuming you want to explicitly set some values - .setNotNull("productName") - .setNotNull("companyName") - .setNotNull("productType") - .setNotNull("upperItem") - .setNotNull("manufactureType") - .setNotNull("manufactureMethod") - .setNotNull("weight") - .setNotNull("reportNumber") - .setNotNull("mainSubstance") - .setNotNull("brand") - .set("grade", 3.5) - .set("reviewCnt", 10L) - .setNotNull("viewCount") - .setNotNull("createdAt") - .setNotNull("createdBy") - .setNotNull("modifiedAt") - .setNotNull("modifiedBy") + .setNotNull("productName") + .setNotNull("barcode") + .setNotNull("imageSource") + .setNotNull("reportNumber") + .setNotNull("safetyStatus") + .setNotNull("viewCount") + .setNotNull("companyName") + .setNotNull("productType") + .setNotNull("issuedDate") + .setNotNull("safetyInspectionStandard") + .setNotNull("upperItem") + .setNotNull("item") + .setNotNull("propose") + .setNotNull("weight") + .setNotNull("usage") + .setNotNull("usagePrecaution") + .setNotNull("firstAid") + .setNotNull("mainSubstance") + .setNotNull("allergicSubstance") + .setNotNull("otherSubstance") + .setNotNull("preservative") + .setNotNull("surfactant") + .setNotNull("fluorescentWhitening") + .setNotNull("manufactureType") + .setNotNull("manufactureMethod") + .setNotNull("violationInfo") + .setNotNull("createdAt") + .setNotNull("createdBy") + .setNotNull("modifiedAt") + .setNotNull("modifiedBy") .sample(); ProductDetailDto productDetailDto = ProductDetailDto.from(mockProduct); when(productService.getProductById(1L)).thenReturn(productDetailDto); - // when & then - mockMvc.perform(get("/product/{id}", 1L)) + mockMvc.perform(get("/product/{productNo}", 1L)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.value.productNo", notNullValue())) - .andExpect(jsonPath("$.value.productName", notNullValue())) - .andExpect(jsonPath("$.value.companyName", notNullValue())) - .andExpect(jsonPath("$.value.productType", notNullValue())) - .andExpect(jsonPath("$.value.upperItem", notNullValue())) - .andExpect(jsonPath("$.value.manufactureType", notNullValue())) - .andExpect(jsonPath("$.value.manufactureMethod", notNullValue())) - .andExpect(jsonPath("$.value.weight", notNullValue())) - .andExpect(jsonPath("$.value.reportNumber", notNullValue())) - .andExpect(jsonPath("$.value.mainSubstance", notNullValue())) - .andExpect(jsonPath("$.value.brand", notNullValue())) - .andExpect(jsonPath("$.value.grade", notNullValue())) - .andExpect(jsonPath("$.value.reviewCnt", notNullValue())) - .andExpect(jsonPath("$.value.viewCount", notNullValue())) - .andExpect(jsonPath("$.value.createdAt", notNullValue())) - .andExpect(jsonPath("$.value.createdBy", notNullValue())) - .andExpect(jsonPath("$.value.modifiedAt", notNullValue())) - .andExpect(jsonPath("$.value.modifiedBy", notNullValue())) + .andExpect(jsonPath("$.value.productName", notNullValue())) + .andExpect(jsonPath("$.value.barcode", notNullValue())) + .andExpect(jsonPath("$.value.imageSource", notNullValue())) + .andExpect(jsonPath("$.value.reportNumber", notNullValue())) + .andExpect(jsonPath("$.value.safetyStatus", notNullValue())) + .andExpect(jsonPath("$.value.viewCount", notNullValue())) + .andExpect(jsonPath("$.value.companyName", notNullValue())) + .andExpect(jsonPath("$.value.productType", notNullValue())) + .andExpect(jsonPath("$.value.issuedDate", notNullValue())) + .andExpect(jsonPath("$.value.safetyInspectionStandard", notNullValue())) + .andExpect(jsonPath("$.value.upperItem", notNullValue())) + .andExpect(jsonPath("$.value.item", notNullValue())) + .andExpect(jsonPath("$.value.propose", notNullValue())) + .andExpect(jsonPath("$.value.weight", notNullValue())) + .andExpect(jsonPath("$.value.usage", notNullValue())) + .andExpect(jsonPath("$.value.usagePrecaution", notNullValue())) + .andExpect(jsonPath("$.value.firstAid", notNullValue())) + .andExpect(jsonPath("$.value.mainSubstance", notNullValue())) + .andExpect(jsonPath("$.value.allergicSubstance", notNullValue())) + .andExpect(jsonPath("$.value.otherSubstance", notNullValue())) + .andExpect(jsonPath("$.value.preservative", notNullValue())) + .andExpect(jsonPath("$.value.surfactant", notNullValue())) + .andExpect(jsonPath("$.value.fluorescentWhitening", notNullValue())) + .andExpect(jsonPath("$.value.manufactureType", notNullValue())) + .andExpect(jsonPath("$.value.manufactureMethod", notNullValue())) + .andExpect(jsonPath("$.value.violationInfo", notNullValue())) + .andExpect(jsonPath("$.value.createdAt", notNullValue())) + .andExpect(jsonPath("$.value.createdBy", notNullValue())) + .andExpect(jsonPath("$.value.modifiedAt", notNullValue())) + .andExpect(jsonPath("$.value.modifiedBy", notNullValue())) .andDo(document("product-id/get-product-id", pathParameters( - parameterWithName("id").description("제품 ID") + parameterWithName("productNo").description("제품번호") ), responseFields( fieldWithPath("status").description("상태 코드"), - fieldWithPath("message").description("응답 메세지"), - fieldWithPath("code").description("비지니스 코드"), - fieldWithPath("value").description("제품 상세 정보"), + fieldWithPath("message").description("응답 메시지"), + fieldWithPath("code").description("비즈니스 코드"), + subsectionWithPath("value").description("제품 목록"), fieldWithPath("value.productNo").description("제품번호"), fieldWithPath("value.productName").description("제품명"), + fieldWithPath("value.barcode").description("바코드"), + fieldWithPath("value.imageSource").description("이미지"), + fieldWithPath("value.reportNumber").description("신고번호"), + fieldWithPath("value.safetyStatus").description("위해우려등급"), + fieldWithPath("value.viewCount").description("조회수"), fieldWithPath("value.companyName").description("제조사"), - fieldWithPath("value.productType").description("제품 유형"), - fieldWithPath("value.upperItem").description("상위 분류"), - fieldWithPath("value.manufactureType").description("제조 타입"), - fieldWithPath("value.manufactureMethod").description("제조 방법"), + fieldWithPath("value.productType").description("제품구분"), + fieldWithPath("value.issuedDate").description("신고년월"), + fieldWithPath("value.safetyInspectionStandard").description("제품검사기준"), + fieldWithPath("value.upperItem").description("품목군"), + fieldWithPath("value.item").description("품목"), + fieldWithPath("value.propose").description("제품용도"), fieldWithPath("value.weight").description("무게"), - fieldWithPath("value.reportNumber").description("보고 번호"), + fieldWithPath("value.usage").description("사용방법"), + fieldWithPath("value.usagePrecaution").description("사용시 주의사항"), + fieldWithPath("value.firstAid").description("응급처치법"), fieldWithPath("value.mainSubstance").description("주요 성분"), - fieldWithPath("value.brand").description("브랜드"), - fieldWithPath("value.grade").description("평점"), - fieldWithPath("value.reviewCnt").description("리뷰 수"), - fieldWithPath("value.viewCount").description("조회수"), - fieldWithPath("value.createdAt").description("생성 날짜"), + fieldWithPath("value.allergicSubstance").description("알러지 반응 가능 물질"), + fieldWithPath("value.otherSubstance").description("기타 물질"), + fieldWithPath("value.preservative").description("보존제"), + fieldWithPath("value.surfactant").description("계면활성제"), + fieldWithPath("value.fluorescentWhitening").description("형광증백제"), + fieldWithPath("value.manufactureType").description("제조구분"), + fieldWithPath("value.manufactureMethod").description("제조방식"), + fieldWithPath("value.violationInfo").description("위반내역"), + fieldWithPath("value.createdAt").description("생성일"), fieldWithPath("value.createdBy").description("생성자"), - fieldWithPath("value.modifiedAt").description("수정 날짜"), + fieldWithPath("value.modifiedAt").description("수정일"), fieldWithPath("value.modifiedBy").description("수정자") ))); verify(productService).getProductById(1L); @@ -201,7 +239,7 @@ class ProductControllerTest extends ControllerTest { .setNotNull("reportNumber") .set("safetyStatus", SafetyStatus.CONCERN) .set("viewCount", 0) - .setNotNull("brand") +// .setNotNull("brand") .setNotNull("upperItem") .setNotNull("createdAt") .setNotNull("createdBy") @@ -244,7 +282,7 @@ class ProductControllerTest extends ControllerTest { fieldWithPath("value.content[*].reportNumber").description("보고서 번호"), fieldWithPath("value.content[*].safetyStatus").description("안전 상태"), fieldWithPath("value.content[*].viewCount").description("조회수"), - fieldWithPath("value.content[*].brand").description("브랜드"), +// fieldWithPath("value.content[*].brand").description("브랜드"), fieldWithPath("value.content[*].upperItem").description("상위 항목 카테고리"), fieldWithPath("value.content[*].createdAt").description("생성 날짜"), fieldWithPath("value.content[*].createdBy").description("생성자"),