From b4d3f04d2707b5670397a0c3cf10c2242cec440f Mon Sep 17 00:00:00 2001 From: nahye Date: Tue, 4 Mar 2025 16:23:47 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Cart,=20LineItem,=20Product=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=B6=94=EA=B0=80=20=ED=9B=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/model/Cart.java | 63 +++++++++++ .../java/com/example/demo/model/LineItem.java | 38 +++++++ .../java/com/example/demo/model/Product.java | 34 ++++++ .../java/com/example/demo/model/CartTest.java | 101 ++++++++++++++++++ .../com/example/demo/model/LineItemTest.java | 25 +++++ .../com/example/demo/model/ProductTest.java | 34 ++++++ 6 files changed, 295 insertions(+) create mode 100644 src/main/java/com/example/demo/model/Cart.java create mode 100644 src/main/java/com/example/demo/model/LineItem.java create mode 100644 src/main/java/com/example/demo/model/Product.java create mode 100644 src/test/java/com/example/demo/model/CartTest.java create mode 100644 src/test/java/com/example/demo/model/LineItemTest.java create mode 100644 src/test/java/com/example/demo/model/ProductTest.java diff --git a/src/main/java/com/example/demo/model/Cart.java b/src/main/java/com/example/demo/model/Cart.java new file mode 100644 index 0000000..15dcd06 --- /dev/null +++ b/src/main/java/com/example/demo/model/Cart.java @@ -0,0 +1,63 @@ +package com.example.demo.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Cart { + + private List lineItems; + private int totalQuantity; + + public Cart(List lineItems) { + this.lineItems = new ArrayList<>(lineItems); + calculateTotalQuantity(); + } + + public List getLineItems() { + return Collections.unmodifiableList(lineItems); + } + + public int getTotalQuantity() { + return totalQuantity; + } + + public void addProduct(String productId, String productOption, int quantity) { + + checkValidQuantity(quantity); + + LineItem lineItem = findLineItem(productId, productOption); + + if (lineItem != null) { + lineItem.addQuantity(quantity); + calculateTotalQuantity(); + return; + } + + lineItem = new LineItem(productId, productOption, quantity); + lineItems.add(lineItem); + calculateTotalQuantity(); + } + + public void checkValidQuantity(int quantity) { + if (totalQuantity + quantity> 20) { + throw new IllegalArgumentException("담을수 있는 수량을 초과했습니다."); + } + } + + private void calculateTotalQuantity() { + this.totalQuantity = lineItems.stream() + .mapToInt(LineItem::getQuantity) + .sum(); + } + + + private LineItem findLineItem(String productId, String productOption) { + return lineItems.stream() + .filter(i -> i.getProductId().equals(productId) + && i.getProductOption().equals(productOption)) + .findFirst() + .orElse(null); + } + +} diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java new file mode 100644 index 0000000..28ef63e --- /dev/null +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -0,0 +1,38 @@ +package com.example.demo.model; + +import java.util.UUID; + +public class LineItem { + + private final String id; + private final String productId; + private final String productOption; + + private int quantity; + + + public LineItem(String productId, String productOption, int quantity) { + this.id = "LineItem-"+ UUID.randomUUID(); + this.productId = productId; + this.productOption = productOption; + this.quantity = quantity; + } + + public int getQuantity() { + return quantity; + } + + public String getProductId() { + return productId; + } + + public String getProductOption() { + return productOption; + } + + + + public void addQuantity(int quantity) { + this.quantity += quantity; + } +} diff --git a/src/main/java/com/example/demo/model/Product.java b/src/main/java/com/example/demo/model/Product.java new file mode 100644 index 0000000..173c720 --- /dev/null +++ b/src/main/java/com/example/demo/model/Product.java @@ -0,0 +1,34 @@ +package com.example.demo.model; + +public class Product { + + private String id; + private String name; + private int price; + + public Product(String id, String name, int price) { + this.id = id; + this.name = name; + this.price = price; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public int getPrice() { + return price; + } + + public void changePrice(int price) { + this.price = price; + } + + public void changeName(String name) { + this.name = name; + } +} diff --git a/src/test/java/com/example/demo/model/CartTest.java b/src/test/java/com/example/demo/model/CartTest.java new file mode 100644 index 0000000..7594be8 --- /dev/null +++ b/src/test/java/com/example/demo/model/CartTest.java @@ -0,0 +1,101 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CartTest { + + private Product product1; + private Product product2; + private String productOption1; + private String productOption2; + + @BeforeEach + void setUp() { + product1 = new Product("product-1", "product #1", 5000); + product2 = new Product("product-2", "product #2", 3000); + + productOption1 = "productOption-1"; + productOption2 = "productOption-2"; + } + + @Test + @DisplayName("빈 장바구니의 수량은 0이다.") + void cartTotalQuantityIsZero() { + Cart cart = new Cart(List.of()); + + assertThat(cart.getTotalQuantity()).isEqualTo(0); + } + + @Test + @DisplayName("빈 장바구니에 물건 추가하면 장바구니의 전체수량은 추가한 수량과 같다.") + void addProduct() { + Cart cart = new Cart(List.of()); + + int quantity = 1; + cart.addProduct(product1.getId(), productOption1, quantity); + + assertThat(cart.getTotalQuantity()).isEqualTo(quantity); + } + + @Test + @DisplayName("장바구니에 이미 있는 물건 추가하면 전체 수량은 이미 있던 수량과 새로 추가하는 수량의 합이다.") + void addExistingProduct() { + + int oldQuantity = 1; + Cart cart = new Cart(List.of( + createLineItem(product1, productOption1, oldQuantity) + )); + + int newQuantity = 1; + cart.addProduct(product1.getId(), productOption1, newQuantity); + + assertThat(cart.getLineItems()).hasSize(1); + assertThat(cart.getTotalQuantity()).isEqualTo(oldQuantity + newQuantity); + } + + @Test + @DisplayName("장바구니에 새로운 있는 물건 추가하면 전체 수량은 이미 있던 물건의 수량과 " + + "새로 추가하는 물건의 수량의 합이다.") + void addNewProduct() { + + int oldQuantity = 1; + Cart cart = new Cart(List.of( + createLineItem(product2, productOption2, oldQuantity) + )); + + int newQuantity = 1; + cart.addProduct(product1.getId(), productOption1, newQuantity); + + assertThat(cart.getLineItems()).hasSize(2); + assertThat(cart.getTotalQuantity()).isEqualTo(oldQuantity + newQuantity); + } + + @Test + @DisplayName("전체 장바구니의 수량이 20개가 넘어가면 예외가 발생한다.") + void totalQuantityCanNotOverLimit() { + Cart cart = new Cart(List.of( + createLineItem(product1, productOption1, 19) + )); + + int newQuantity = 5; + + assertThatThrownBy( + () -> cart.addProduct(product1.getId(), productOption1, newQuantity) + ).isInstanceOf(IllegalArgumentException.class); + + } + + + + private LineItem createLineItem(Product product, String productOption, int quantity) { + return new LineItem(product.getId(), productOption, quantity); + } + +} diff --git a/src/test/java/com/example/demo/model/LineItemTest.java b/src/test/java/com/example/demo/model/LineItemTest.java new file mode 100644 index 0000000..2810c57 --- /dev/null +++ b/src/test/java/com/example/demo/model/LineItemTest.java @@ -0,0 +1,25 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + + +class LineItemTest { + + @Test + void addQuantity() { + + String productId = "productId-1"; + String productOption = "productOption-1"; + int quantity = 5; + int delta = 5; + LineItem lineItem = new LineItem(productId, productOption, quantity); + + lineItem.addQuantity(delta); + + assertThat(lineItem.getQuantity()).isEqualTo(quantity + delta); + + } + +} diff --git a/src/test/java/com/example/demo/model/ProductTest.java b/src/test/java/com/example/demo/model/ProductTest.java new file mode 100644 index 0000000..95f796f --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductTest.java @@ -0,0 +1,34 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProductTest { + + private Product product; + + @BeforeEach + void setUp() { + product = new Product("product-1", "Product #1", 5000); + } + + @Test + void changeProductName(){ + + String newName = "NewProduct"; + product.changeName(newName); + + assertThat(product.getName()).isEqualTo(newName); + } + + @Test + void changeProductPrice(){ + int newPrice = 10000; + product.changePrice(newPrice); + + assertThat(product.getPrice()).isEqualTo(newPrice); + } + +} From 074e5edc11665333154cdbb78b5d1945a97115f2 Mon Sep 17 00:00:00 2001 From: nahye Date: Tue, 4 Mar 2025 20:10:25 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1=20=ED=9B=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cart의 checkValidQuantity() 수정 - LineItem에 isSameProduct() 추가 - LineItemId, ProductId, ProductOption VO 추가 - Test 추가 --- .../java/com/example/demo/model/Cart.java | 17 +++++----- .../java/com/example/demo/model/LineItem.java | 27 +++++++--------- .../com/example/demo/model/LineItemId.java | 12 +++++++ .../java/com/example/demo/model/Product.java | 6 ++-- .../com/example/demo/model/ProductId.java | 6 ++++ .../com/example/demo/model/ProductOption.java | 7 +++++ .../java/com/example/demo/model/CartTest.java | 14 ++++----- .../example/demo/model/LineItemIdTest.java | 30 ++++++++++++++++++ .../com/example/demo/model/LineItemTest.java | 31 ++++++++++++++----- .../com/example/demo/model/ProductIdTest.java | 20 ++++++++++++ .../example/demo/model/ProductOptionTest.java | 28 +++++++++++++++++ .../com/example/demo/model/ProductTest.java | 2 +- 12 files changed, 159 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/example/demo/model/LineItemId.java create mode 100644 src/main/java/com/example/demo/model/ProductId.java create mode 100644 src/main/java/com/example/demo/model/ProductOption.java create mode 100644 src/test/java/com/example/demo/model/LineItemIdTest.java create mode 100644 src/test/java/com/example/demo/model/ProductIdTest.java create mode 100644 src/test/java/com/example/demo/model/ProductOptionTest.java diff --git a/src/main/java/com/example/demo/model/Cart.java b/src/main/java/com/example/demo/model/Cart.java index 15dcd06..d640ab7 100644 --- a/src/main/java/com/example/demo/model/Cart.java +++ b/src/main/java/com/example/demo/model/Cart.java @@ -22,25 +22,26 @@ public int getTotalQuantity() { return totalQuantity; } - public void addProduct(String productId, String productOption, int quantity) { + public void addProduct(ProductId productId, ProductOption productOption, int quantity) { - checkValidQuantity(quantity); LineItem lineItem = findLineItem(productId, productOption); if (lineItem != null) { - lineItem.addQuantity(quantity); + lineItem.addQuantity(quantity, productOption); calculateTotalQuantity(); + checkValidQuantity(); return; } lineItem = new LineItem(productId, productOption, quantity); lineItems.add(lineItem); calculateTotalQuantity(); + checkValidQuantity(); } - public void checkValidQuantity(int quantity) { - if (totalQuantity + quantity> 20) { + public void checkValidQuantity() { + if (totalQuantity > 20) { throw new IllegalArgumentException("담을수 있는 수량을 초과했습니다."); } } @@ -52,10 +53,10 @@ private void calculateTotalQuantity() { } - private LineItem findLineItem(String productId, String productOption) { + private LineItem findLineItem(ProductId productId, ProductOption productOption) { return lineItems.stream() - .filter(i -> i.getProductId().equals(productId) - && i.getProductOption().equals(productOption)) + .filter(lineItem -> + lineItem.isSameProduct(productId,productOption)) .findFirst() .orElse(null); } diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java index 28ef63e..79204f8 100644 --- a/src/main/java/com/example/demo/model/LineItem.java +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -1,18 +1,17 @@ package com.example.demo.model; -import java.util.UUID; public class LineItem { - private final String id; - private final String productId; - private final String productOption; + private final LineItemId id; + private final ProductId productId; + private final ProductOption productOption; private int quantity; - public LineItem(String productId, String productOption, int quantity) { - this.id = "LineItem-"+ UUID.randomUUID(); + public LineItem(ProductId productId, ProductOption productOption, int quantity) { + this.id = LineItemId.generate(); this.productId = productId; this.productOption = productOption; this.quantity = quantity; @@ -22,17 +21,15 @@ public int getQuantity() { return quantity; } - public String getProductId() { - return productId; - } - public String getProductOption() { - return productOption; + public void addQuantity(int quantity, ProductOption productOption) { + if(!this.productOption.equals(productOption)) { + return; + } + this.quantity += quantity; } - - - public void addQuantity(int quantity) { - this.quantity += quantity; + public boolean isSameProduct(ProductId productId, ProductOption productOption) { + return this.productId.equals(productId) && this.productOption.equals(productOption); } } diff --git a/src/main/java/com/example/demo/model/LineItemId.java b/src/main/java/com/example/demo/model/LineItemId.java new file mode 100644 index 0000000..c0e1f57 --- /dev/null +++ b/src/main/java/com/example/demo/model/LineItemId.java @@ -0,0 +1,12 @@ +package com.example.demo.model; + +import java.util.UUID; + +public record LineItemId( + String id +) { + + public static LineItemId generate() { + return new LineItemId("lineItemId-" + UUID.randomUUID()); + } +} diff --git a/src/main/java/com/example/demo/model/Product.java b/src/main/java/com/example/demo/model/Product.java index 173c720..f0b49f1 100644 --- a/src/main/java/com/example/demo/model/Product.java +++ b/src/main/java/com/example/demo/model/Product.java @@ -2,17 +2,17 @@ public class Product { - private String id; + private ProductId id; private String name; private int price; - public Product(String id, String name, int price) { + public Product(ProductId id, String name, int price) { this.id = id; this.name = name; this.price = price; } - public String getId() { + public ProductId getId() { return id; } diff --git a/src/main/java/com/example/demo/model/ProductId.java b/src/main/java/com/example/demo/model/ProductId.java new file mode 100644 index 0000000..4951e6b --- /dev/null +++ b/src/main/java/com/example/demo/model/ProductId.java @@ -0,0 +1,6 @@ +package com.example.demo.model; + +public record ProductId ( + String id +){ +} diff --git a/src/main/java/com/example/demo/model/ProductOption.java b/src/main/java/com/example/demo/model/ProductOption.java new file mode 100644 index 0000000..aa16fdb --- /dev/null +++ b/src/main/java/com/example/demo/model/ProductOption.java @@ -0,0 +1,7 @@ +package com.example.demo.model; + +public record ProductOption( + String color, + String size +) { +} diff --git a/src/test/java/com/example/demo/model/CartTest.java b/src/test/java/com/example/demo/model/CartTest.java index 7594be8..972473e 100644 --- a/src/test/java/com/example/demo/model/CartTest.java +++ b/src/test/java/com/example/demo/model/CartTest.java @@ -13,16 +13,16 @@ class CartTest { private Product product1; private Product product2; - private String productOption1; - private String productOption2; + private ProductOption productOption1; + private ProductOption productOption2; @BeforeEach void setUp() { - product1 = new Product("product-1", "product #1", 5000); - product2 = new Product("product-2", "product #2", 3000); + product1 = new Product(new ProductId("product-1"), "product #1", 5000); + product2 = new Product(new ProductId("product-2"), "product #2", 3000); - productOption1 = "productOption-1"; - productOption2 = "productOption-2"; + productOption1 = new ProductOption("red", "M"); + productOption2 = new ProductOption("black", "L"); } @Test @@ -94,7 +94,7 @@ void totalQuantityCanNotOverLimit() { - private LineItem createLineItem(Product product, String productOption, int quantity) { + private LineItem createLineItem(Product product, ProductOption productOption, int quantity) { return new LineItem(product.getId(), productOption, quantity); } diff --git a/src/test/java/com/example/demo/model/LineItemIdTest.java b/src/test/java/com/example/demo/model/LineItemIdTest.java new file mode 100644 index 0000000..0883233 --- /dev/null +++ b/src/test/java/com/example/demo/model/LineItemIdTest.java @@ -0,0 +1,30 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class LineItemIdTest { + + @Test + @DisplayName("같은 값이면 같은 객체로 취급된다.") + void sameLineItemId() { + LineItemId id1 = new LineItemId("LineItem-1"); + LineItemId id2 = new LineItemId("LineItem-1"); + + assertThat(id1).isEqualTo(id2); + } + + @Test + @DisplayName("generate()를 사용하면 서로다른 아이디가 생성된다.") + void lineItemIdIsUnique() { + LineItemId id1 = LineItemId.generate(); + LineItemId id2 = LineItemId.generate(); + + assertThat(id1).isNotEqualTo(id2); + } + + +} diff --git a/src/test/java/com/example/demo/model/LineItemTest.java b/src/test/java/com/example/demo/model/LineItemTest.java index 2810c57..659e53f 100644 --- a/src/test/java/com/example/demo/model/LineItemTest.java +++ b/src/test/java/com/example/demo/model/LineItemTest.java @@ -1,5 +1,6 @@ package com.example.demo.model; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -8,18 +9,34 @@ class LineItemTest { @Test - void addQuantity() { - - String productId = "productId-1"; - String productOption = "productOption-1"; - int quantity = 5; + @DisplayName("같은 상품과 옵션일 경우, 수량을 추가할 수 있어야 한다.") + void isSameProduct(){ + ProductId productId = new ProductId("productId"); + ProductOption productOption = new ProductOption("red", "M"); + int quantity = 1; int delta = 5; - LineItem lineItem = new LineItem(productId, productOption, quantity); - lineItem.addQuantity(delta); + LineItem lineItem = new LineItem(productId, productOption, quantity); + lineItem.addQuantity(delta, productOption); + assertThat(lineItem.isSameProduct(productId, new ProductOption("red", "M"))).isTrue(); assertThat(lineItem.getQuantity()).isEqualTo(quantity + delta); } + @Test + @DisplayName("같은 상품이라도 옵션이 다르면, 수량은 추가되지 않는다.") + void sameProductAndDifferentOption(){ + ProductId productId = new ProductId("productId"); + ProductOption productOption = new ProductOption("red", "M"); + int quantity = 1; + int delta = 5; + LineItem lineItem = new LineItem(productId, productOption, quantity); + + ProductOption productOption2 = new ProductOption("black", "M"); + lineItem.addQuantity(delta, productOption2); + + assertThat(lineItem.isSameProduct(productId, productOption2)).isFalse(); + assertThat(lineItem.getQuantity()).isEqualTo(quantity); + } } diff --git a/src/test/java/com/example/demo/model/ProductIdTest.java b/src/test/java/com/example/demo/model/ProductIdTest.java new file mode 100644 index 0000000..e8361fa --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductIdTest.java @@ -0,0 +1,20 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class ProductIdTest { + + @Test + @DisplayName("같은 값이면 같은 객체로 취급된다.") + void sameProductId() { + ProductId id1 = new ProductId("productId-1"); + ProductId id2 = new ProductId("productId-1"); + + assertThat(id1).isEqualTo(id2); + } + +} diff --git a/src/test/java/com/example/demo/model/ProductOptionTest.java b/src/test/java/com/example/demo/model/ProductOptionTest.java new file mode 100644 index 0000000..9f148df --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductOptionTest.java @@ -0,0 +1,28 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProductOptionTest { + + @Test + @DisplayName("값이 같으면 같은 객체로 취급된다.") + void sameValue() { + ProductOption option1 = new ProductOption("red", "M"); + ProductOption option2 = new ProductOption("red", "M"); + + assertThat(option1).isEqualTo(option2); + } + + @Test + @DisplayName("값이 다르면 다른 객체로 취급된다.") + void differentValue() { + ProductOption option1 = new ProductOption("red", "M"); + ProductOption option2 = new ProductOption("black", "M"); + + assertThat(option1).isNotEqualTo(option2); + } + +} diff --git a/src/test/java/com/example/demo/model/ProductTest.java b/src/test/java/com/example/demo/model/ProductTest.java index 95f796f..6838595 100644 --- a/src/test/java/com/example/demo/model/ProductTest.java +++ b/src/test/java/com/example/demo/model/ProductTest.java @@ -11,7 +11,7 @@ class ProductTest { @BeforeEach void setUp() { - product = new Product("product-1", "Product #1", 5000); + product = new Product(new ProductId("product-1"), "Product #1", 5000); } @Test