Skip to content

[4주차] 장바구니 만들기#8

Open
moonnahye wants to merge 2 commits intodal-lab:mainfrom
moonnahye:4-week-cart
Open

[4주차] 장바구니 만들기#8
moonnahye wants to merge 2 commits intodal-lab:mainfrom
moonnahye:4-week-cart

Conversation

@moonnahye
Copy link

@moonnahye moonnahye commented Mar 4, 2025

Summary by CodeRabbit

  • New Features
    • 향상된 장바구니 기능: 상품 추가 및 수량 관리가 개선되어, 사용자가 더욱 원활하게 쇼핑할 수 있습니다.
    • 강화된 상품 관리: 상품 정보 업데이트와 주문 항목 관리가 직관적으로 이루어지며, 최대 수량 제한 기능이 적용되었습니다.
    • 새로운 LineItem, Product, ProductId, ProductOption, LineItemId 클래스 추가로 상품 및 주문 항목 관리가 더욱 효율적으로 이루어집니다.
  • Bug Fixes
    • 장바구니의 총 수량이 20을 초과하지 않도록 하는 유효성 검사 추가.

@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2025

"""

Walkthrough

새로운 Cart, LineItem, Product 클래스를 추가했습니다. Cart 클래스는 LineItem 객체 목록을 관리하며 제품 추가 시 수량 유효성 검사, 기존 항목 업데이트와 총 수량 재계산 기능을 수행합니다. LineItem 클래스는 주문 항목의 정보를 캡슐화하고, 수량 증분 기능을 포함합니다. Product 클래스는 상품의 식별자, 이름, 가격을 관리하며 수정할 수 있습니다. 또한, 각 클래스에 대해 JUnit 5와 AssertJ 기반의 단위 테스트가 추가되어 기본 기능이 검증됩니다.

Changes

파일 변경 요약
src/main/java/com/example/demo/model/Cart.java
src/main/java/com/example/demo/model/LineItem.java
src/main/java/com/example/demo/model/Product.java
새로운 모델 클래스 추가: Cart는 LineItem 목록 관리 및 제품 추가/수량 계산 기능 구현, LineItem은 주문 항목 데이터 및 수량 증분 기능, Product는 상품 정보 관리 및 수정 기능 구현
src/test/java/com/example/demo/model/CartTest.java
src/test/java/com/example/demo/model/LineItemTest.java
src/test/java/com/example/demo/model/ProductTest.java
새로운 단위 테스트 클래스 추가: 각 모델 클래스 기능에 대한 검증 테스트 추가
src/main/java/com/example/demo/model/LineItemId.java
src/main/java/com/example/demo/model/ProductId.java
src/main/java/com/example/demo/model/ProductOption.java
새로운 레코드 클래스 추가: LineItemId, ProductId, ProductOption으로 각 항목의 고유 식별자 및 속성 정의
src/test/java/com/example/demo/model/LineItemIdTest.java
src/test/java/com/example/demo/model/ProductIdTest.java
src/test/java/com/example/demo/model/ProductOptionTest.java
새로운 테스트 클래스 추가: 각 레코드 클래스의 기능 검증 테스트 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Cart
    participant LineItem

    User->>Cart: addProduct(productId, productOption, quantity)
    Cart->>Cart: checkValidQuantity(quantity)
    alt 상품이 이미 있는 경우
        Cart->>LineItem: addQuantity(quantity)
    else 새로운 상품인 경우
        Cart->>LineItem: 생성 new LineItem(productId, productOption, quantity)
        Cart-->>Cart: 항목 목록에 추가
    end
    Cart->>Cart: calculateTotalQuantity()
    Cart->>User: 반환: 업데이트된 총 수량
Loading

Poem

나는 숲을 달리는 귀여운 토끼,
Cart 속 제품들 모아 반짝이는 꿈을 꾸네.
LineItem과 함께 수량을 더하며,
Product의 변화를 살포시 노래하네.
코드 숲 속, 행복한 우리 이야기! 🐇✨
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (19)
src/main/java/com/example/demo/model/Product.java (4)

5-7: 필드 유효성 검증 추가 고려

현재 구현에서는 id, name, price 필드에 대한 유효성 검증이 없습니다. price가 음수가 될 수 있거나 name이 null이나 빈 문자열이 될 수 있는 상황을 방지하기 위한 검증 로직을 추가하는 것이 좋습니다.

private String id;
private String name;
private int price;

public Product(String id, String name, int price) {
+    if (id == null || id.isBlank()) {
+        throw new IllegalArgumentException("상품 ID는 필수입니다.");
+    }
+    if (name == null || name.isBlank()) {
+        throw new IllegalArgumentException("상품 이름은 필수입니다.");
+    }
+    if (price < 0) {
+        throw new IllegalArgumentException("상품 가격은 0 이상이어야 합니다.");
+    }
    this.id = id;
    this.name = name;
    this.price = price;
}

27-29: 가격 변경 메서드에 유효성 검증 추가

changePrice 메서드에서 price가 음수가 될 수 있는 상황을 방지하기 위한 검증 로직을 추가하는 것이 좋습니다.

public void changePrice(int price) {
+    if (price < 0) {
+        throw new IllegalArgumentException("상품 가격은 0 이상이어야 합니다.");
+    }
    this.price = price;
}

3-34: equals(), hashCode(), toString() 메서드 구현 고려

현재 Product 클래스는 equals(), hashCode(), toString() 메서드를 구현하지 않고 있습니다. 컬렉션에서 Product 객체를 사용하거나 디버깅 시 유용하게 사용할 수 있으므로 이러한 메서드의 구현을 고려해보세요.

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Product product = (Product) o;
    return Objects.equals(id, product.id);
}

@Override
public int hashCode() {
    return Objects.hash(id);
}

@Override
public String toString() {
    return "Product{" +
            "id='" + id + '\'' +
            ", name='" + name + '\'' +
            ", price=" + price +
            '}';
}

6-7: 가격 필드 타입 고려

price 필드의 타입이 int로 선언되어 있습니다. 화폐 값을 표현할 때는 소수점 이하 값의 정확한 계산을 위해 BigDecimal 사용을 고려해볼 수 있습니다. 현재 시스템에서 정수형 가격으로 충분하다면 현재 구현을 유지해도 됩니다.

src/test/java/com/example/demo/model/LineItemTest.java (2)

10-23: 추가 테스트 케이스 고려

현재는 수량을 증가시키는 기본적인 케이스만 테스트하고 있습니다. 다음과 같은 추가적인 테스트 케이스를 고려해볼 수 있습니다:

  1. 음수 수량 추가 시 동작 검증
  2. 수량이 0일 때의 동작 검증
  3. 최대 허용 수량 초과 시 예외 발생 여부 검증

10-11: @DisplayName 어노테이션 사용 고려

테스트 메서드의 가독성을 높이기 위해 CartTest 클래스처럼 @DisplayName 어노테이션을 사용하는 것을 고려해보세요.

@Test
+ @DisplayName("수량 추가 시 LineItem의 수량이 올바르게 증가해야 한다")
void addQuantity() {
src/test/java/com/example/demo/model/ProductTest.java (3)

17-24: @DisplayName 어노테이션 사용 고려

테스트 메서드의 가독성을 높이기 위해 CartTest 클래스처럼 @DisplayName 어노테이션을 사용하는 것을 고려해보세요.

@Test
+ @DisplayName("상품 이름이 올바르게 변경되어야 한다")
void changeProductName(){

26-32: @DisplayName 어노테이션 사용 고려

테스트 메서드의 가독성을 높이기 위해 CartTest 클래스처럼 @DisplayName 어노테이션을 사용하는 것을 고려해보세요.

@Test
+ @DisplayName("상품 가격이 올바르게 변경되어야 한다")
void changeProductPrice(){

8-33: 추가 테스트 케이스 고려

현재는 기본적인 이름과 가격 변경에 대한 테스트만 포함되어 있습니다. 다음과 같은 추가 테스트 케이스를 고려해볼 수 있습니다:

  1. null이나 빈 문자열로 이름 변경 시 예외 발생 여부
  2. 음수 가격으로 변경 시 예외 발생 여부
  3. getId() 메서드에 대한 테스트
src/test/java/com/example/demo/model/CartTest.java (4)

64-65: DisplayName 텍스트 오타 수정

DisplayName에 약간의 오타가 있습니다. "장바구니에 새로운 있는 물건 추가하면"은 "장바구니에 새로운 물건 추가하면"으로 수정하는 것이 자연스럽습니다.

@DisplayName("장바구니에 새로운 있는 물건 추가하면 전체 수량은 이미 있던 물건의 수량과 " +
-            "새로 추가하는 물건의 수량의 합이다.")
+            "새로 추가하는 물건의 수량의 합이다.")

95-96: 불필요한 빈 줄 제거

코드 가독성을 위해 불필요한 빈 줄을 제거하는 것이 좋습니다.

    }



    private LineItem createLineItem(Product product, String productOption, int quantity) {

12-101: 추가 테스트 케이스 고려

현재는 기본적인 장바구니 기능에 대한 테스트만 포함되어 있습니다. 다음과 같은 추가 테스트 케이스를 고려해볼 수 있습니다:

  1. 수량이 0인 상품 추가 시 동작 검증
  2. 음수 수량 추가 시 예외 발생 여부 검증
  3. 상품 제거 기능이 있다면 이에 대한 테스트

82-93: 예외 메시지 검증 추가

현재는 예외 타입만 검증하고 있습니다. 예외 메시지도 함께 검증하면 더 정확한 테스트가 됩니다.

assertThatThrownBy(
        () -> cart.addProduct(product1.getId(), productOption1, newQuantity)
-).isInstanceOf(IllegalArgumentException.class);
+).isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("장바구니 최대 수량");
src/main/java/com/example/demo/model/LineItem.java (3)

14-19: 생성자에 수량 유효성 검사 추가 필요

수량(quantity)이 음수인 경우에 대한 유효성 검사가 없습니다. 음수 수량은 의미가 없으므로 검증 로직을 추가하는 것이 좋습니다.

public LineItem(String productId, String productOption, int quantity) {
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("수량은 0보다 커야 합니다.");
+    }
    this.id = "LineItem-"+ UUID.randomUUID();
    this.productId = productId;
    this.productOption = productOption;
    this.quantity = quantity;
}

35-37: addQuantity 메소드에 유효성 검사 추가 필요

quantity에 음수 값이 전달될 경우 의도치 않게 총 수량이 감소할 수 있습니다. 양수 값만 허용하도록 검사 로직을 추가하는 것이 좋습니다.

public void addQuantity(int quantity) {
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("추가 수량은 0보다 커야 합니다.");
+    }
    this.quantity += quantity;
}

1-38: id 필드에 대한 getter 메소드 추가 고려

현재 id 필드에 대한 getter 메소드가 없습니다. 다른 모든 필드에는 getter가 있는데, 식별자인 id에 접근할 방법이 없으면 향후 LineItem을 식별해야 하는 작업에서 문제가 발생할 수 있습니다.

public String getProductOption() {
    return productOption;
}

+ public String getId() {
+     return id;
+ }

public void addQuantity(int quantity) {
src/main/java/com/example/demo/model/Cart.java (3)

42-46: checkValidQuantity 메소드 접근 제어자 수정 고려

이 메소드는 addProduct 내에서만 사용되는데 public으로 선언되어 있습니다. 외부에서 직접 호출되는 것을 방지하기 위해 private으로 변경하는 것이 좋습니다.

- public void checkValidQuantity(int quantity) {
+ private void checkValidQuantity(int quantity) {
    if (totalQuantity + quantity> 20) {
        throw new IllegalArgumentException("담을수 있는 수량을 초과했습니다.");
    }
}

43-43: 연산자 앞에 공백 추가 필요

'>' 연산자 앞에 공백이 누락되어 가독성이 떨어집니다.

- if (totalQuantity + quantity> 20) {
+ if (totalQuantity + quantity > 20) {

1-63: 기본 생성자 추가 고려

빈 장바구니로 시작할 수 있는 기본 생성자가 없습니다. 사용자 편의성을 위해 빈 ArrayList로 초기화하는 기본 생성자를 추가하는 것이 좋습니다.

public Cart(List<LineItem> lineItems) {
    this.lineItems = new ArrayList<>(lineItems);
    calculateTotalQuantity();
}

+ public Cart() {
+     this.lineItems = new ArrayList<>();
+     this.totalQuantity = 0;
+ }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ff8df4 and b4d3f04.

📒 Files selected for processing (6)
  • src/main/java/com/example/demo/model/Cart.java (1 hunks)
  • src/main/java/com/example/demo/model/LineItem.java (1 hunks)
  • src/main/java/com/example/demo/model/Product.java (1 hunks)
  • src/test/java/com/example/demo/model/CartTest.java (1 hunks)
  • src/test/java/com/example/demo/model/LineItemTest.java (1 hunks)
  • src/test/java/com/example/demo/model/ProductTest.java (1 hunks)
🔇 Additional comments (12)
src/main/java/com/example/demo/model/Product.java (1)

1-34: 기본적인 Product 클래스 구현이 잘 되어 있습니다.

상품을 표현하는 클래스가 간결하게 구현되어 있으며, 적절한 접근 제어와 getter/setter 메서드를 제공하고 있습니다.

src/test/java/com/example/demo/model/LineItemTest.java (1)

8-24: 테스트 코드 작성이 잘 되어 있습니다.

LineItem 클래스의 addQuantity 메서드에 대한 테스트가 간결하고 명확하게 작성되어 있습니다.

src/test/java/com/example/demo/model/ProductTest.java (1)

8-33: 테스트 코드가 잘 작성되어 있습니다.

Product 클래스의 필드 변경 메서드들에 대한 테스트가 간결하고 명확하게 작성되어 있습니다. @beforeeach를 사용하여 각 테스트 전에 Product 객체를 초기화하는 부분도 잘 구현되어 있습니다.

src/test/java/com/example/demo/model/CartTest.java (1)

12-101: 잘 구조화된 테스트 코드입니다.

Cart 클래스의 다양한 기능을 검증하는 테스트 케이스들이 적절히 구현되어 있습니다. @DisplayName 어노테이션을 사용하여 테스트의 목적을 명확히 설명하고 있으며, 다양한 시나리오를 검증하고 있습니다.

src/main/java/com/example/demo/model/LineItem.java (2)

7-11: 클래스 필드 구성이 적절합니다.

final 키워드를 사용해 불변 필드를 명확히 지정했고, 수량만 변경 가능하도록 설계한 점이 좋습니다.


21-31: getter 메소드 구현이 적절합니다.

필요한 모든 정보에 접근할 수 있는 getter 메소드가 잘 구현되어 있습니다.

src/main/java/com/example/demo/model/Cart.java (6)

9-10: 필드 캡슐화가 적절합니다.

Cart 클래스의 필드들이 private으로 적절하게 캡슐화되어 있습니다.


12-15: 방어적 복사와 초기화 로직이 우수합니다.

생성자에서 전달받은 LineItem 목록의 방어적 복사본을 만들고, 총 수량을 계산하는 초기화 로직이 잘 구현되어 있습니다.


17-19: 불변 리스트 반환으로 안전한 접근을 제공합니다.

Collections.unmodifiableList를 사용하여 외부에서 내부 데이터를 직접 수정할 수 없도록 보호한 점이 좋습니다.


25-40: addProduct 메소드 구현이 견고합니다.

제품 추가 로직이 명확하게 구현되어 있습니다. 기존 상품이 있는 경우 수량을 업데이트하고, 없는 경우 새 LineItem을 생성하는 방식이 적절합니다.


48-52: 스트림 API를 사용한 효율적인 총 수량 계산

스트림 API를 활용하여 총 수량을 계산하는 방식이 간결하고 효율적입니다.


55-61: findLineItem 메소드가 잘 구현되어 있습니다.

스트림 API를 활용하여 조건에 맞는 LineItem을 찾는 로직이 간결하고 명확합니다.

@gemini-code-assist
Copy link

Warning

Gemini is experiencing higher than usual traffic and was unable to create the summary. Please try again in a few hours by commenting /gemini summary.


public void addProduct(String productId, String productOption, int quantity) {

checkValidQuantity(quantity);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 수량 외에 다른 복잡한 조건이 들어가면 어떻게 될까요?
만약 UoW, 트랜잭션이 존재하는 환경에라면, 모든 변경을 수행 후 마지막에 검사해서 예외를 발생시키는 게 좋습니다. (지금은 그런 게 없긴 하죠.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 수정해보도록하겠습니다!

Comment on lines 57 to 58
.filter(i -> i.getProductId().equals(productId)
&& i.getProductOption().equals(productOption))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동일 상품인지 검사하는 게 복잡해지면 어떻게 될까요? 옵션도 여러 개인 경우도 포함해서요. 예를 들어 구두를 판매한다고 할 때, 색상과 크기 두 가지 옵션을 가진 경우가 있을 수 있겠죠.
코드 레벨에서 뭔가 불편한 느낌이 들면 설계를 개선할 좋은 기회를 잡은 겁니다. 이런 건 LineItem에 위임하면 이런 모양이 되고, 앞으로 유지보수할 때 크게 도움이 될 겁니다.

Suggested change
.filter(i -> i.getProductId().equals(productId)
&& i.getProductOption().equals(productOption))
.filter(lineItem -> lineItem.isSameProduct(productId, productOption))

Comment on lines 7 to 9
private final String id;
private final String productId;
private final String productOption;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

셋 다 전형적인 VO가 되야 할 것으로 보입니다.

특히, productOption은 어떤 건가요? 그냥 문자열로 아무렇게나 전달해도 되는 건가요? String으로는 아무 것도 알 수가 없습니다. 도메인 지식이 담기지 않은 거죠.

- Cart의 checkValidQuantity() 수정
- LineItem에 isSameProduct() 추가
- LineItemId, ProductId, ProductOption VO 추가
- Test 추가
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (9)
src/main/java/com/example/demo/model/ProductOption.java (1)

1-7: 유효성 검증 로직 추가를 고려해보세요.

현재 구현에서는 color나 size에 대한 유효성 검증이 없습니다. 비즈니스 요구사항에 따라 null이나 빈 문자열 체크, 또는 허용 가능한 색상/사이즈 목록 검증이 필요할 수 있습니다.

public record ProductOption(
        String color,
        String size
) {
+    public ProductOption {
+        if (color == null || color.isBlank()) {
+            throw new IllegalArgumentException("색상은 반드시 지정해야 합니다");
+        }
+        if (size == null || size.isBlank()) {
+            throw new IllegalArgumentException("사이즈는 반드시 지정해야 합니다");
+        }
+    }
}
src/test/java/com/example/demo/model/LineItemIdTest.java (1)

1-30: 추가적인 테스트 케이스를 고려해보세요.

기본적인 동등성 테스트와 고유성 테스트는 잘 작성되었지만, 다음과 같은 추가 테스트 케이스를 고려해 볼 수 있습니다:

  1. null 또는 빈 문자열로 LineItemId를 생성하는 경우
  2. toString() 메서드의 출력 형식 검증
  3. 생성된 ID의 형식 검증 (정규표현식 등 사용)
@Test
@DisplayName("ID 값이 null이거나 빈 문자열이면 예외가 발생한다.")
void invalidId() {
    assertThatThrownBy(() -> new LineItemId(null))
        .isInstanceOf(IllegalArgumentException.class);
    
    assertThatThrownBy(() -> new LineItemId(""))
        .isInstanceOf(IllegalArgumentException.class);
}

@Test
@DisplayName("생성된 ID는 예상된 형식을 가진다.")
void idFormat() {
    LineItemId id = LineItemId.generate();
    assertThat(id.id()).startsWith("lineItemId-");
    assertThat(id.id()).matches("lineItemId-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
}
src/main/java/com/example/demo/model/LineItemId.java (2)

5-12: ID 유효성 검증 로직 추가를 고려해보세요.

현재 구현에서는 ID 값에 대한 유효성 검증이 없습니다. ID가 null이거나 빈 문자열인 경우를 방지하기 위한 검증 로직을 추가하는 것이 좋을 것 같습니다.

public record LineItemId(
     String id
) {
+    public LineItemId {
+        if (id == null || id.isBlank()) {
+            throw new IllegalArgumentException("ID는 반드시 지정해야 합니다");
+        }
+    }

    public static LineItemId generate() {
        return new LineItemId("lineItemId-" + UUID.randomUUID());
    }
}

9-11: 메서드 문서화를 고려해보세요.

generate() 메서드에 JavaDoc 주석을 추가하여 메서드의 목적과 동작 방식을 문서화하는 것이 좋을 것 같습니다.

+    /**
+     * 고유한 LineItemId를 생성합니다.
+     * 이 메서드는 UUID를 사용하여 충돌 가능성이 거의 없는 ID를 생성합니다.
+     *
+     * @return 새로운 LineItemId 인스턴스
+     */
    public static LineItemId generate() {
        return new LineItemId("lineItemId-" + UUID.randomUUID());
    }
src/test/java/com/example/demo/model/ProductOptionTest.java (1)

1-28: 추가 테스트 케이스를 고려해보세요.

기본적인 동등성 테스트는 잘 작성되었지만, 다음과 같은 추가 테스트 케이스를 고려해 볼 수 있습니다:

  1. 색상은 같지만 사이즈가 다른 경우
  2. null 값에 대한 처리 (유효성 검증 로직 추가 시)
  3. 대소문자 구분 여부 (예: "Red"와 "red"가 같은지 다른지)
@Test
@DisplayName("사이즈가 다르면 다른 객체로 취급된다.")
void differentSize() {
    ProductOption option1 = new ProductOption("red", "M");
    ProductOption option2 = new ProductOption("red", "L");

    assertThat(option1).isNotEqualTo(option2);
}

@Test
@DisplayName("색상과 사이즈 모두 다르면 다른 객체로 취급된다.")
void differentColorAndSize() {
    ProductOption option1 = new ProductOption("red", "M");
    ProductOption option2 = new ProductOption("black", "L");

    assertThat(option1).isNotEqualTo(option2);
}
src/test/java/com/example/demo/model/ProductIdTest.java (1)

6-7: 정적 임포트 최적화가 필요합니다.

import static org.junit.jupiter.api.Assertions.*;를 임포트했지만 실제로 이 클래스의 어떤 메서드도 사용하지 않고 있습니다. 불필요한 임포트는 제거하는 것이 좋습니다.

import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
src/test/java/com/example/demo/model/LineItemTest.java (1)

22-22: 테스트 코드 중복 제거 가능성이 있습니다.

22행에서 ProductOption 객체를 새로 생성하여 비교하고 있는데, 이미 선언된 productOption 변수를 재사용하는 것이 더 명확할 것 같습니다.

-assertThat(lineItem.isSameProduct(productId, new ProductOption("red", "M"))).isTrue();
+assertThat(lineItem.isSameProduct(productId, productOption)).isTrue();
src/test/java/com/example/demo/model/CartTest.java (1)

63-78: 새 상품 추가 테스트에 개선 가능성이 있습니다.

테스트 이름과 설명이 "새로운 있는 물건"으로 약간 모호합니다. "새로운 상품"이나 "다른 상품"으로 수정하는 것이 더 명확할 것 같습니다.

@Test
-@DisplayName("장바구니에 새로운 있는 물건 추가하면 전체 수량은 이미 있던 물건의 수량과 " +
-        "새로 추가하는 물건의 수량의 합이다.")
+@DisplayName("장바구니에 새로운 상품을 추가하면 전체 수량은 이미 있던 상품의 수량과 " +
+        "새로 추가하는 상품의 수량의 합이다.")
void addNewProduct() {
src/main/java/com/example/demo/model/LineItem.java (1)

25-30: addQuantity 메서드 동작 방식 개선 고려가 필요합니다.

현재 메서드는 productOption이 다른 경우 조용히 반환됩니다. 이는 디버깅이 어려울 수 있습니다. 예외를 던지거나 결과를 반환하는 방식으로 변경하는 것이 더 명확할 수 있습니다.

-public void addQuantity(int quantity, ProductOption productOption) {
-    if(!this.productOption.equals(productOption)) {
-        return;
-    }
-    this.quantity += quantity;
+public boolean addQuantity(int quantity, ProductOption productOption) {
+    if(!this.productOption.equals(productOption)) {
+        return false;
+    }
+    this.quantity += quantity;
+    return true;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d3f04 and 074e5ed.

📒 Files selected for processing (12)
  • src/main/java/com/example/demo/model/Cart.java (1 hunks)
  • src/main/java/com/example/demo/model/LineItem.java (1 hunks)
  • src/main/java/com/example/demo/model/LineItemId.java (1 hunks)
  • src/main/java/com/example/demo/model/Product.java (1 hunks)
  • src/main/java/com/example/demo/model/ProductId.java (1 hunks)
  • src/main/java/com/example/demo/model/ProductOption.java (1 hunks)
  • src/test/java/com/example/demo/model/CartTest.java (1 hunks)
  • src/test/java/com/example/demo/model/LineItemIdTest.java (1 hunks)
  • src/test/java/com/example/demo/model/LineItemTest.java (1 hunks)
  • src/test/java/com/example/demo/model/ProductIdTest.java (1 hunks)
  • src/test/java/com/example/demo/model/ProductOptionTest.java (1 hunks)
  • src/test/java/com/example/demo/model/ProductTest.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/example/demo/model/ProductId.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/com/example/demo/model/Product.java
  • src/test/java/com/example/demo/model/ProductTest.java
  • src/main/java/com/example/demo/model/Cart.java
🔇 Additional comments (19)
src/main/java/com/example/demo/model/ProductOption.java (1)

3-7: 좋은 레코드 구현입니다!

Java 레코드를 사용하여 상품 옵션(색상, 사이즈)을 불변 객체로 관리하는 설계가 잘 되었습니다. 레코드를 사용함으로써 equals(), hashCode(), toString() 메서드를 자동으로 구현하여 코드가 간결해졌습니다.

src/test/java/com/example/demo/model/LineItemIdTest.java (2)

11-18: 테스트 케이스가 명확합니다.

동일한 ID 값을 가진 LineItemId 객체들이 동등하게 취급되는지 확인하는 테스트가 잘 작성되었습니다. DisplayName을 한글로 명확하게 작성하여 테스트의 목적이 잘 드러납니다.


20-27: 생성 메서드 동작 테스트가 적절합니다.

generate() 메서드가 매번 고유한 ID를 생성하는지 검증하는 테스트가 잘 작성되었습니다. 이는 LineItemId의 핵심 요구사항을 잘 검증하고 있습니다.

src/main/java/com/example/demo/model/LineItemId.java (2)

5-7: 간결한 레코드 정의입니다.

LineItemId를 Java 레코드로 정의하여 불변 객체로 관리하는 접근 방식이 좋습니다. 이는 ID와 같은 값 객체에 적합한 설계입니다.


9-11: UUID를 활용한 ID 생성 방식이 적절합니다.

UUID를 사용하여 고유한 ID를 생성하는 방식은 충돌 가능성이 매우 낮아 적절합니다. 또한 접두사를 붙여 ID의 출처를 명확히 하였습니다.

src/test/java/com/example/demo/model/ProductOptionTest.java (2)

10-17: 동등성 테스트가 잘 작성되었습니다.

같은 값을 가진 ProductOption 객체들이 equals() 메서드에 의해 동등하게 취급되는지 확인하는 테스트가 명확합니다. DisplayName을 통해 테스트의 목적이 잘 드러납니다.


19-26: 비동등성 테스트가 잘 작성되었습니다.

다른 값을 가진 ProductOption 객체들이 서로 다르게 취급되는지 확인하는 테스트가 명확합니다. 현재는 색상만 다른 경우를 테스트하고 있습니다.

src/test/java/com/example/demo/model/ProductIdTest.java (1)

11-18: 테스트 구현이 잘 되어 있습니다.

ProductId의 동등성 비교가 올바르게 구현되었는지 확인하는 테스트입니다. 같은 문자열 값을 가진 두 ProductId 객체가 동등하게 취급되는지 확인하고 있습니다.

src/test/java/com/example/demo/model/LineItemTest.java (2)

13-24: isSameProduct 테스트 코드가 명확합니다.

LineItem 클래스의 addQuantity 메서드와 isSameProduct 메서드를 잘 검증하고 있습니다. 같은 상품과 옵션일 경우 수량 추가가 제대로 작동하는지 확인하는 테스트입니다.


29-41: sameProductAndDifferentOption 테스트 구현이 명확합니다.

같은 상품이지만 다른 옵션일 경우 수량이 추가되지 않는 기능을 잘 검증하고 있습니다.

src/test/java/com/example/demo/model/CartTest.java (6)

19-26: 테스트 설정이 잘 구성되어 있습니다.

테스트에 필요한 객체들을 @beforeeach를 통해 초기화하여 중복 코드를 효과적으로 줄였습니다.


28-34: 빈 장바구니 테스트가 잘 구현되어 있습니다.

빈 장바구니의 초기 수량이 0인지 확인하는 기본적인 테스트로 적절합니다.


36-45: 빈 장바구니에 상품 추가 테스트가 명확합니다.

빈 장바구니에 상품을 추가할 때 장바구니의 총 수량이 올바르게 반영되는지 검증하고 있습니다.


47-61: 기존 상품 추가 테스트가 잘 구현되어 있습니다.

장바구니에 이미 있는 상품을 추가할 때 수량이 올바르게 합산되는지 확인하는 테스트입니다.


80-93: 수량 제한 테스트가 잘 구현되어 있습니다.

장바구니의 총 수량이 제한(20개)을 초과할 때 예외가 발생하는지 확인하는 테스트입니다. 예외 검증이 적절하게 구현되어 있습니다.


97-99: helper 메서드가 잘 구현되어 있습니다.

테스트 코드의 중복을 줄이기 위한 helper 메서드가 적절히 구현되어 있습니다.

src/main/java/com/example/demo/model/LineItem.java (3)

4-10: LineItem 클래스 설계에 Value Object 패턴 적용 고려가 필요합니다.

현재 LineItem 클래스는 내부 상태를 변경할 수 있는 메서드(addQuantity)를 가지고 있어 완전한 Value Object가 아닙니다. 불변 객체로 만들어 값 객체의 특성을 살리는 것을 고려해보세요.


13-18: 생성자가 적절히 구현되어 있습니다.

모든 필요한 필드를 초기화하고 있고, ID는 자동 생성 방식을 사용하고 있습니다.


32-34: isSameProduct 메서드가 잘 구현되어 있습니다.

상품 ID와 옵션을 모두 비교하여 동일 상품인지 확인하는 로직이 명확합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants