diff --git a/product-order-service/src/main/java/com/example/productorderservice/order/Order.java b/product-order-service/src/main/java/com/example/productorderservice/order/Order.java index 829af2d3..610704b9 100644 --- a/product-order-service/src/main/java/com/example/productorderservice/order/Order.java +++ b/product-order-service/src/main/java/com/example/productorderservice/order/Order.java @@ -12,7 +12,7 @@ import javax.persistence.*; @Table(name = "orders") @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -class Order { +public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -29,4 +29,7 @@ class Order { this.quantity = quantity; } + public int getTotalPrice() { + return product.getDiscountedPrice() * quantity; + } } diff --git a/product-order-service/src/main/java/com/example/productorderservice/product/DiscountPolicy.java b/product-order-service/src/main/java/com/example/productorderservice/product/DiscountPolicy.java index 7f2e8f3f..beed732c 100644 --- a/product-order-service/src/main/java/com/example/productorderservice/product/DiscountPolicy.java +++ b/product-order-service/src/main/java/com/example/productorderservice/product/DiscountPolicy.java @@ -1,6 +1,19 @@ package com.example.productorderservice.product; public enum DiscountPolicy { - NONE + NONE { + @Override + int applyDiscount(int price) { + return price; + } + }, + FIX_1000_AMOUNT { + @Override + int applyDiscount(int price) { + return Math.max(price - 1000, 0); + } + } + ; + abstract int applyDiscount(int price); } diff --git a/product-order-service/src/main/java/com/example/productorderservice/product/Product.java b/product-order-service/src/main/java/com/example/productorderservice/product/Product.java index bd5a8a4f..65638b70 100644 --- a/product-order-service/src/main/java/com/example/productorderservice/product/Product.java +++ b/product-order-service/src/main/java/com/example/productorderservice/product/Product.java @@ -38,4 +38,8 @@ class Product { this.price = price; this.discountPolicy = discountPolicy; } + + public int getDiscountedPrice() { + return discountPolicy.applyDiscount(price); + } } diff --git a/product-order-service/src/test/java/com/example/productorderservice/order/OrderTest.java b/product-order-service/src/test/java/com/example/productorderservice/order/OrderTest.java new file mode 100644 index 00000000..37620e99 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/order/OrderTest.java @@ -0,0 +1,19 @@ +package com.example.productorderservice.order; + +import com.example.productorderservice.product.DiscountPolicy; +import com.example.productorderservice.product.Product; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class OrderTest { + + @Test + void getTotalPrice() { + Order order = new Order(new Product("상품", 1000, DiscountPolicy.NONE), 2); + + int totalPrice = order.getTotalPrice(); + + assertThat(totalPrice).isEqualTo(2000); + } +} \ No newline at end of file diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/ConsolePaymentGateway.java b/product-order-service/src/test/java/com/example/productorderservice/payment/ConsolePaymentGateway.java new file mode 100644 index 00000000..af1622f2 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/ConsolePaymentGateway.java @@ -0,0 +1,9 @@ +package com.example.productorderservice.payment; + +public class ConsolePaymentGateway implements PaymentGateway { + @Override + public void execute(int totalPrice, String cardNumber) { + System.out.println("결제 완료"); + + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/Payment.java b/product-order-service/src/test/java/com/example/productorderservice/payment/Payment.java new file mode 100644 index 00000000..c65c1c80 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/Payment.java @@ -0,0 +1,34 @@ +package com.example.productorderservice.payment; + +import com.example.productorderservice.order.Order; +import org.springframework.util.Assert; + +class Payment { + + private Long id; + private final Order order; + private final String cardNumber; + + public Payment(Order order, String cardNumber) { + Assert.notNull(order, "주문은 필수입니다."); + Assert.hasText(cardNumber, "카드번호는 필수입니다."); + this.order = order; + this.cardNumber = cardNumber; + } + + public void assign(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public int getPrice() { + return order.getTotalPrice(); + } + + public String getCardNumber() { + return cardNumber; + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentAdapter.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentAdapter.java new file mode 100644 index 00000000..77601eab --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentAdapter.java @@ -0,0 +1,30 @@ +package com.example.productorderservice.payment; + +import com.example.productorderservice.order.Order; +import com.example.productorderservice.product.DiscountPolicy; +import com.example.productorderservice.product.Product; + +class PaymentAdapter implements PaymentPort { + private final PaymentGateway paymentGateway; + private final PaymentRepository paymentRepository; + + PaymentAdapter(PaymentGateway paymentGateway, PaymentRepository paymentRepository) { + this.paymentGateway = paymentGateway; + this.paymentRepository = paymentRepository; + } + + @Override + public Order getOrder(Long orderId) { + return new Order(new Product("상품1", 1000, DiscountPolicy.NONE), 2); + } + + @Override + public void pay(int totalPrice, String cardNumber) { + paymentGateway.execute(totalPrice, cardNumber); + } + + @Override + public void save(Payment payment) { + paymentRepository.save(payment); + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentGateway.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentGateway.java new file mode 100644 index 00000000..2255bc44 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentGateway.java @@ -0,0 +1,5 @@ +package com.example.productorderservice.payment; + +interface PaymentGateway { + void execute(int totalPrice, String cardNumber); +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentPort.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentPort.java new file mode 100644 index 00000000..ae489ccb --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentPort.java @@ -0,0 +1,11 @@ +package com.example.productorderservice.payment; + +import com.example.productorderservice.order.Order; + +interface PaymentPort { + Order getOrder(Long orderId); + + void pay(int totalPrice, String cardNumber); + + void save(Payment payment); +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRepository.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRepository.java new file mode 100644 index 00000000..ae64d6be --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRepository.java @@ -0,0 +1,14 @@ +package com.example.productorderservice.payment; + +import java.util.HashMap; +import java.util.Map; + +class PaymentRepository { + private final Map persistence = new HashMap<>(); + private Long sequence = 0L; + + public void save(Payment payment) { + payment.assign(++sequence); + persistence.put(payment.getId(), payment); + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRequest.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRequest.java new file mode 100644 index 00000000..f78f8130 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentRequest.java @@ -0,0 +1,11 @@ +package com.example.productorderservice.payment; + +import org.springframework.util.Assert; + +record PaymentRequest(Long orderId, String cardNumber) { + + PaymentRequest { + Assert.notNull(orderId, "주문 ID는 필수입니다."); + Assert.hasText(cardNumber, "카드번호는 필수입니다."); + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentService.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentService.java new file mode 100644 index 00000000..f09a037b --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentService.java @@ -0,0 +1,20 @@ +package com.example.productorderservice.payment; + +import com.example.productorderservice.order.Order; + +class PaymentService { + private final PaymentPort paymentPort; + + PaymentService(PaymentPort paymentPort) { + this.paymentPort = paymentPort; + } + + public void payment(PaymentRequest request) { + final Order order = paymentPort.getOrder(request.orderId()); + + final Payment payment = new Payment(order, request.cardNumber()); + + paymentPort.pay(payment.getPrice(), payment.getCardNumber()); + paymentPort.save(payment); + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentServiceTest.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentServiceTest.java new file mode 100644 index 00000000..5cdb9fcb --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentServiceTest.java @@ -0,0 +1,27 @@ +package com.example.productorderservice.payment; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class PaymentServiceTest { + + private PaymentService paymentService; + private PaymentPort paymentPort; + + @BeforeEach + void setUp() { + final PaymentGateway paymentGateway = new ConsolePaymentGateway(); + final PaymentRepository paymentRepository= new PaymentRepository(); + paymentPort = new PaymentAdapter(paymentGateway, paymentRepository); + paymentService = new PaymentService(paymentPort); + } + + @Test + void 상품주문() { + + final PaymentRequest request = PaymentSteps.주문결제요청_생성(); + + paymentService.payment(request); + } + +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentSteps.java b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentSteps.java new file mode 100644 index 00000000..48f1235f --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/payment/PaymentSteps.java @@ -0,0 +1,10 @@ +package com.example.productorderservice.payment; + +public class PaymentSteps { + + public static PaymentRequest 주문결제요청_생성() { + final Long orderId = 1L; + final String cardNumber = "1234-1234-1234-1234"; + return new PaymentRequest(orderId, cardNumber); + } +} diff --git a/product-order-service/src/test/java/com/example/productorderservice/product/DiscountPolicyTest.java b/product-order-service/src/test/java/com/example/productorderservice/product/DiscountPolicyTest.java new file mode 100644 index 00000000..43d193d6 --- /dev/null +++ b/product-order-service/src/test/java/com/example/productorderservice/product/DiscountPolicyTest.java @@ -0,0 +1,33 @@ +package com.example.productorderservice.product; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class DiscountPolicyTest { + + @Test + void applyDiscount_NONE() { + final int price = 1000; + final int discountedPrice = DiscountPolicy.NONE.applyDiscount(price); + + assertThat(discountedPrice).isEqualTo(price); + } + + @Test + void applyDiscount_FIX_1000_AMOUNT() { + final int price = 2000; + final int discountedPrice = DiscountPolicy.FIX_1000_AMOUNT.applyDiscount(price); + + assertThat(discountedPrice).isEqualTo(1000); + } + + @Test + void applyDiscount_FIX_1000_AMOUNT_over() { + final int price = 500; + final int discountedPrice = DiscountPolicy.FIX_1000_AMOUNT.applyDiscount(price); + + assertThat(discountedPrice).isEqualTo(0); + } + +} \ No newline at end of file diff --git a/product-order-service/src/test/java/com/example/productorderservice/product/ProductTest.java b/product-order-service/src/test/java/com/example/productorderservice/product/ProductTest.java index fc62600e..cbeb7d82 100644 --- a/product-order-service/src/test/java/com/example/productorderservice/product/ProductTest.java +++ b/product-order-service/src/test/java/com/example/productorderservice/product/ProductTest.java @@ -16,4 +16,22 @@ class ProductTest { assertThat(product.getPrice()).isEqualTo(2000); } + @Test + void none_discounted_product() { + Product product = new Product("상품명", 1000, DiscountPolicy.NONE); + + int discountedPrice = product.getDiscountedPrice(); + + assertThat(discountedPrice).isEqualTo(1000); + } + + @Test + void fix_1000_discounted_product() { + Product product = new Product("상품명", 2000, DiscountPolicy.FIX_1000_AMOUNT); + + int discountedPrice = product.getDiscountedPrice(); + + assertThat(discountedPrice).isEqualTo(1000); + } + } \ No newline at end of file