diff --git a/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/service/SaveRoundProductServiceTest.java b/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/service/SaveRoundProductServiceTest.java index 9515180..8782b01 100644 --- a/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/service/SaveRoundProductServiceTest.java +++ b/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/service/SaveRoundProductServiceTest.java @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import io.github.sejoung.product.persistence.repository.ProductRepository; -import io.github.sejoung.product.persistence.util.TestUtil; +import io.github.sejoung.product.persistence.util.JpaTestUtil; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -27,7 +27,7 @@ class SaveRoundProductServiceTest { @Test void saveRoundProduct() { - var actual = service.saveRoundProduct(TestUtil.defaultRoundProduct()); + var actual = service.saveRoundProduct(JpaTestUtil.defaultRoundProduct()); log.debug("{}",actual); assertThat(actual.getProductId()).isNotNull(); diff --git a/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/TestUtil.java b/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/JpaTestUtil.java similarity index 92% rename from adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/TestUtil.java rename to adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/JpaTestUtil.java index 94eb87e..cb26b5f 100644 --- a/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/TestUtil.java +++ b/adapters/jpa-persistence/src/test/java/io/github/sejoung/product/persistence/util/JpaTestUtil.java @@ -4,7 +4,7 @@ import io.github.sejoung.product.entities.Category; import io.github.sejoung.product.entities.Product; import io.github.sejoung.product.entities.RoundProduct; -public interface TestUtil { +public interface JpaTestUtil { static RoundProduct defaultRoundProduct() { return new RoundProduct(null, 1L, Category.ProductType.ROUND, Product.ProductStatus.CREATE, "회차권", 2); } diff --git a/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductStatus.java b/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductStatus.java new file mode 100644 index 0000000..1e9452c --- /dev/null +++ b/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductStatus.java @@ -0,0 +1,5 @@ +package io.github.sejoung.product.rest.constants; + +public enum ProductStatus { + CREATE, DELETE, TEMPORARY, PERMANENTLY_DELETE +} diff --git a/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductType.java b/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductType.java new file mode 100644 index 0000000..6c41500 --- /dev/null +++ b/adapters/rest/src/main/java/io/github/sejoung/product/rest/constants/ProductType.java @@ -0,0 +1,5 @@ +package io.github.sejoung.product.rest.constants; + +public enum ProductType { + ROUND, PERIOD +} \ No newline at end of file diff --git a/adapters/rest/src/main/java/io/github/sejoung/product/rest/controller/SaveRoundProductController.java b/adapters/rest/src/main/java/io/github/sejoung/product/rest/controller/SaveRoundProductController.java new file mode 100644 index 0000000..f9655e3 --- /dev/null +++ b/adapters/rest/src/main/java/io/github/sejoung/product/rest/controller/SaveRoundProductController.java @@ -0,0 +1,32 @@ +package io.github.sejoung.product.rest.controller; + +import javax.validation.Valid; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import io.github.sejoung.product.rest.dto.SaveRoundProduct; +import io.github.sejoung.product.rest.mapper.SaveRoundProductMapper; +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +public class SaveRoundProductController { + + private final SaveRoundProductInUseCase saveRoundProductInUseCase; + + public SaveRoundProductController( + SaveRoundProductInUseCase saveRoundProductInUseCase) { + this.saveRoundProductInUseCase = saveRoundProductInUseCase; + } + + @PostMapping("/product/round") + public SaveRoundProduct roundSave( + @Valid @RequestBody SaveRoundProduct dto) { + log.debug("{}", dto); + var command = saveRoundProductInUseCase.save(SaveRoundProductMapper.toEntity(dto)); + return SaveRoundProductMapper.toDto(command); + } +} diff --git a/adapters/rest/src/main/java/io/github/sejoung/product/rest/dto/SaveRoundProduct.java b/adapters/rest/src/main/java/io/github/sejoung/product/rest/dto/SaveRoundProduct.java new file mode 100644 index 0000000..ab5f70d --- /dev/null +++ b/adapters/rest/src/main/java/io/github/sejoung/product/rest/dto/SaveRoundProduct.java @@ -0,0 +1,46 @@ +package io.github.sejoung.product.rest.dto; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import io.github.sejoung.product.rest.constants.ProductStatus; +import io.github.sejoung.product.rest.constants.ProductType; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +public class SaveRoundProduct { + + private final Long productId; + + @NotNull + private final Long categoryId; + + @NotNull + private final ProductType productType; + + @NotNull + private final ProductStatus status; + + @NotEmpty + private final String productName; + + @Min(1) + @Max(99) + private final Integer count; + + @Builder + private SaveRoundProduct(Long productId, Long categoryId, + ProductType productType, ProductStatus status, String productName, Integer count) { + this.productId = productId; + this.categoryId = categoryId; + this.productType = productType; + this.status = status; + this.productName = productName; + this.count = count; + } +} diff --git a/adapters/rest/src/main/java/io/github/sejoung/product/rest/mapper/SaveRoundProductMapper.java b/adapters/rest/src/main/java/io/github/sejoung/product/rest/mapper/SaveRoundProductMapper.java new file mode 100644 index 0000000..02c4bdf --- /dev/null +++ b/adapters/rest/src/main/java/io/github/sejoung/product/rest/mapper/SaveRoundProductMapper.java @@ -0,0 +1,28 @@ +package io.github.sejoung.product.rest.mapper; + +import io.github.sejoung.product.entities.Product; +import io.github.sejoung.product.rest.constants.ProductType; +import io.github.sejoung.product.rest.dto.SaveRoundProduct; +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; + +public interface SaveRoundProductMapper { + static SaveRoundProductInUseCase.SaveRoundProductCommand toEntity(SaveRoundProduct dto) { + return SaveRoundProductInUseCase.SaveRoundProductCommand.builder() + .productName(dto.getProductName()) + .categoryId(dto.getCategoryId()) + .productId(dto.getProductId()) + .status(Product.ProductStatus.valueOf(dto.getStatus().name())) + .count(dto.getCount()) + .build(); + } + + static SaveRoundProduct toDto(SaveRoundProductInUseCase.SaveRoundProductCommand command) { + return SaveRoundProduct.builder() + .productType(ProductType.valueOf(command.getProductType().name())) + .productId(command.getProductId()) + .productName(command.getProductName()) + .categoryId(command.getCategoryId()) + .count(command.getCount()) + .build(); + } +} diff --git a/adapters/rest/src/main/resources/application.yml b/adapters/rest/src/main/resources/application.yml new file mode 100644 index 0000000..47fbb02 --- /dev/null +++ b/adapters/rest/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8080 \ No newline at end of file diff --git a/adapters/rest/src/main/resources/logback-spring.xml b/adapters/rest/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..23f0277 --- /dev/null +++ b/adapters/rest/src/main/resources/logback-spring.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/adapters/rest/src/test/java/io/github/sejoung/product/rest/TestApplication.java b/adapters/rest/src/test/java/io/github/sejoung/product/rest/TestApplication.java new file mode 100644 index 0000000..23e8042 --- /dev/null +++ b/adapters/rest/src/test/java/io/github/sejoung/product/rest/TestApplication.java @@ -0,0 +1,15 @@ +package io.github.sejoung.product.rest; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import io.github.sejoung.product.rest.util.SaveRoundProductInUseCaseStub; +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; + +@SpringBootApplication +public class TestApplication { + @Bean + public SaveRoundProductInUseCase saveRoundProductInUseCase() { + return new SaveRoundProductInUseCaseStub(); + } +} diff --git a/adapters/rest/src/test/java/io/github/sejoung/product/rest/constants/ProductTypeTest.java b/adapters/rest/src/test/java/io/github/sejoung/product/rest/constants/ProductTypeTest.java new file mode 100644 index 0000000..60ecaff --- /dev/null +++ b/adapters/rest/src/test/java/io/github/sejoung/product/rest/constants/ProductTypeTest.java @@ -0,0 +1,18 @@ +package io.github.sejoung.product.rest.constants; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import io.github.sejoung.product.entities.Category; + +class ProductTypeTest { + + @Test + void valueOf() { + var actal = ProductType.valueOf(Category.ProductType.ROUND.name()); + + assertThat(actal).isNotNull(); + } +} \ No newline at end of file diff --git a/adapters/rest/src/test/java/io/github/sejoung/product/rest/controller/SaveRoundProductControllerTest.java b/adapters/rest/src/test/java/io/github/sejoung/product/rest/controller/SaveRoundProductControllerTest.java new file mode 100644 index 0000000..9882557 --- /dev/null +++ b/adapters/rest/src/test/java/io/github/sejoung/product/rest/controller/SaveRoundProductControllerTest.java @@ -0,0 +1,46 @@ +package io.github.sejoung.product.rest.controller; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +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.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.github.sejoung.product.rest.util.RestTestUtil; +import io.github.sejoung.product.rest.util.SaveRoundProductInUseCaseStub; +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; + +@WebMvcTest(controllers = SaveRoundProductController.class) +class SaveRoundProductControllerTest { + + private static final String URL = "/product/round"; + + @Autowired + private MockMvc mockMvc; + + @DisplayName("회차권 API 테스트") + @Test + void saveRoundProduct() throws Exception { + + var objectMapper = new ObjectMapper(); + var json = objectMapper.writeValueAsString(RestTestUtil.defaultSaveRoundProductCommand(null)); + mockMvc.perform(post(URL) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + + } +} \ No newline at end of file diff --git a/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/RestTestUtil.java b/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/RestTestUtil.java new file mode 100644 index 0000000..a1e5428 --- /dev/null +++ b/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/RestTestUtil.java @@ -0,0 +1,18 @@ +package io.github.sejoung.product.rest.util; + +import io.github.sejoung.product.entities.Product; +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; + +public interface RestTestUtil { + + static SaveRoundProductInUseCase.SaveRoundProductCommand defaultSaveRoundProductCommand(Long productId) { + return SaveRoundProductInUseCase.SaveRoundProductCommand.builder() + .count(1) + .status(Product.ProductStatus.CREATE) + .productId(productId) + .productName("회차권") + .categoryId(1L) + .build(); + } + +} diff --git a/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/SaveRoundProductInUseCaseStub.java b/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/SaveRoundProductInUseCaseStub.java new file mode 100644 index 0000000..79e2f99 --- /dev/null +++ b/adapters/rest/src/test/java/io/github/sejoung/product/rest/util/SaveRoundProductInUseCaseStub.java @@ -0,0 +1,19 @@ +package io.github.sejoung.product.rest.util; + +import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SaveRoundProductInUseCaseStub implements SaveRoundProductInUseCase { + @Override + public SaveRoundProductCommand save(SaveRoundProductCommand command) { + log.debug("{}", command); + return SaveRoundProductCommand.builder() + .categoryId(command.getCategoryId()) + .productName(command.getProductName()) + .productId(1L) + .status(command.getStatus()) + .count(command.getCount()) + .build(); + } +} diff --git a/domain/src/main/java/io/github/sejoung/product/mapper/SaveRoundProductCommandMapper.java b/domain/src/main/java/io/github/sejoung/product/mapper/SaveRoundProductCommandMapper.java index 0350acd..15be8ee 100644 --- a/domain/src/main/java/io/github/sejoung/product/mapper/SaveRoundProductCommandMapper.java +++ b/domain/src/main/java/io/github/sejoung/product/mapper/SaveRoundProductCommandMapper.java @@ -1,14 +1,20 @@ package io.github.sejoung.product.mapper; +import io.github.sejoung.product.entities.Product; import io.github.sejoung.product.entities.RoundProduct; import io.github.sejoung.product.usecases.port.in.SaveRoundProductInUseCase; public interface SaveRoundProductCommandMapper { static SaveRoundProductInUseCase.SaveRoundProductCommand toDto(RoundProduct roundProduct) { - return new SaveRoundProductInUseCase.SaveRoundProductCommand(roundProduct.getProductId(), - roundProduct.getCategory().getCategoryId(), roundProduct.getCategory().getProductType(), - roundProduct.getStatus(), roundProduct.getProductName(), roundProduct.getCount()); + return SaveRoundProductInUseCase.SaveRoundProductCommand.builder() + .productName(roundProduct.getProductName()) + .productId(roundProduct.getProductId()) + .status( + Product.ProductStatus.valueOf(roundProduct.getStatus().name())) + .categoryId(roundProduct.getCategory().getCategoryId()) + .count(roundProduct.getCount()) + .build(); } static RoundProduct toEntity(SaveRoundProductInUseCase.SaveRoundProductCommand command) { diff --git a/domain/src/main/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCase.java b/domain/src/main/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCase.java index ddc3446..7ef43a7 100644 --- a/domain/src/main/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCase.java +++ b/domain/src/main/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCase.java @@ -9,14 +9,17 @@ import io.github.sejoung.product.entities.Category; import io.github.sejoung.product.entities.Product; import io.github.sejoung.product.validating.SelfValidating; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.ToString; public interface SaveRoundProductInUseCase { SaveRoundProductCommand save(SaveRoundProductCommand command); @Getter + @ToString @EqualsAndHashCode(callSuper = false) final class SaveRoundProductCommand extends SelfValidating { @@ -38,11 +41,12 @@ public interface SaveRoundProductInUseCase { @Max(99) private final Integer count; - public SaveRoundProductCommand(Long productId, Long categoryId, Category.ProductType productType, + @Builder + private SaveRoundProductCommand(Long productId, Long categoryId, Product.ProductStatus status, String productName, Integer count) { this.productId = productId; this.categoryId = categoryId; - this.productType = productType; + this.productType = Category.ProductType.ROUND; this.status = status; this.productName = productName; this.count = count; diff --git a/domain/src/test/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCaseTest.java b/domain/src/test/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCaseTest.java index 2465e59..d0928d1 100644 --- a/domain/src/test/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCaseTest.java +++ b/domain/src/test/java/io/github/sejoung/product/usecases/port/in/SaveRoundProductInUseCaseTest.java @@ -10,7 +10,6 @@ import org.junit.jupiter.api.Test; import io.github.sejoung.product.entities.Category; import io.github.sejoung.product.entities.Product; - class SaveRoundProductInUseCaseTest { @DisplayName("Commend 회차권 count는 99 이하여야 합니다") @@ -18,8 +17,13 @@ class SaveRoundProductInUseCaseTest { void validationSaveRoundProductCommand() { Throwable exception = assertThrows(ConstraintViolationException.class, () -> { - var command = new SaveRoundProductInUseCase.SaveRoundProductCommand(null, 1L, Category.ProductType.ROUND, - Product.ProductStatus.CREATE, "2회권", 999); + SaveRoundProductInUseCase.SaveRoundProductCommand.builder() + .categoryId(1L) + .status(Product.ProductStatus.CREATE) + .productName("안녕") + .count(999) + .build(); + }); assertEquals("count: 99 이하여야 합니다", exception.getMessage()); diff --git a/domain/src/test/java/io/github/sejoung/product/usecases/service/SaveRoundProductServiceTest.java b/domain/src/test/java/io/github/sejoung/product/usecases/service/SaveRoundProductServiceTest.java index 563c4e8..3c2c9d5 100644 --- a/domain/src/test/java/io/github/sejoung/product/usecases/service/SaveRoundProductServiceTest.java +++ b/domain/src/test/java/io/github/sejoung/product/usecases/service/SaveRoundProductServiceTest.java @@ -22,8 +22,12 @@ class SaveRoundProductServiceTest { @DisplayName("회차권 저장") @Test void saveTest() { - var command = new SaveRoundProductInUseCase.SaveRoundProductCommand(null, 1L, Category.ProductType.ROUND, - Product.ProductStatus.CREATE, "2회권", 2); + var command = SaveRoundProductInUseCase.SaveRoundProductCommand.builder() + .productName("회차권") + .count(99) + .categoryId(1L) + .status(Product.ProductStatus.CREATE) + .build(); var actual = service.save(command); Assertions.assertEquals(99, actual.getProductId()); }