Skip to content

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

Open
ramyo564 wants to merge 14 commits intodal-lab:mainfrom
ramyo564:yohan-DDD
Open

[4주차] 장바구니 만들기#3
ramyo564 wants to merge 14 commits intodal-lab:mainfrom
ramyo564:yohan-DDD

Conversation

@ramyo564
Copy link

@ramyo564 ramyo564 commented Nov 28, 2024

Summary by CodeRabbit

  • 새로운 기능

    • MongoDB 클라이언트 통합으로 데이터베이스와의 상호작용 가능.
    • 장바구니 관리 기능 추가: 항목 추가, 수량 확인 및 장바구니 내용 검색.
    • 사용자 정의 예외 처리 기능 추가: 총 수량 초과 시 예외 발생.
    • ProductCartItem 모델 추가로 장바구니 아이템 관리 기능 강화.
  • 버그 수정

    • 장바구니의 총 수량 및 항목 관리 로직 개선.
  • 테스트

    • MongoDB 클라이언트 및 장바구니 관련 기능에 대한 단위 테스트 추가.
    • ProductIdCartItemId의 고유 ID 생성 관련 테스트 추가.

ramyo564 and others added 5 commits October 22, 2024 12:57
1. 장바구니에 상품 추가
- 장바구니가 비어있을 경우 장바구니에 동일한 상품이 없다면 해당 상품 추가
- 장바구니에 동일한 상품이 이미 있다면 상품의 수량 증가
- 장바니의 전체 상품 수량의 총 합은 20을 넘길 수 없음

2. 장바구니에서 상품목록 확인
- 장바구니에 담긴 상품의 종류와 수량 체크

3. 장바구니 비우기
@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2024

Walkthrough

이번 변경 사항은 Spring Boot 애플리케이션에 MongoDB 통합을 추가하는 여러 파일의 업데이트를 포함합니다. build.gradle.kts 파일에 MongoDB 드라이버 의존성이 추가되었으며, Application 클래스에 MongoDB 클라이언트를 생성하는 메서드가 추가되었습니다. 또한, 쇼핑 카트를 관리하는 CartCartItem 클래스를 새로 도입하고, 이와 관련된 여러 예외 및 ID 생성 클래스를 추가했습니다. 마지막으로, MongoDB와 관련된 테스트 클래스도 새로 추가되었습니다.

Changes

파일 경로 변경 요약
build.gradle.kts MongoDB 드라이버 의존성 추가: org.mongodb:mongodb-driver-core:5.2.0, org.mongodb:mongodb-driver-sync:5.2.0
src/main/java/com/example/demo/Application.java MongoDB 클라이언트를 생성하는 mongoClient() 메서드 추가
src/main/java/com/example/demo/exceptions/ExceedTotalQuantity.java ExceedTotalQuantity 사용자 정의 예외 클래스 추가
src/main/java/com/example/demo/models/Cart.java Cart 클래스 추가, 아이템 관리 및 수량 체크 메서드 포함
src/main/java/com/example/demo/models/CartItem.java CartItem 클래스 추가, 아이템의 수량 관리 메서드 포함
src/main/java/com/example/demo/models/CartItemId.java CartItemId 레코드 추가, 고유 ID 생성 기능 포함
src/main/java/com/example/demo/models/GenerateId.java 고유 ID 생성을 위한 GenerateId 레코드 추가
src/main/java/com/example/demo/models/Product.java Product 레코드 추가, 제품 ID 필드 포함
src/main/java/com/example/demo/models/ProductId.java ProductId 레코드 추가, 고유 ID 생성 기능 포함
src/test/java/com/example/demo/MongoDbTest.java MongoDB 클라이언트 기능 검증을 위한 테스트 클래스 추가
src/test/java/com/example/demo/models/CartItemIdTest.java CartItemId 클래스의 ID 생성 검증 테스트 추가
src/test/java/com/example/demo/models/CartItemTest.java CartItem 모델의 기능 검증을 위한 테스트 클래스 추가
src/test/java/com/example/demo/models/CartTest.java Cart 클래스의 기능 검증을 위한 테스트 클래스 추가
src/test/java/com/example/demo/models/ProductIdTest.java ProductId 클래스의 ID 생성 검증 테스트 추가

Poem

🐰
카트에 담긴 꿈과 희망,
MongoDB와 함께하는 새로운 시작.
수량 체크는 예외를 부르고,
아이템 추가는 즐거운 일!
Rabbit의 기쁨, 여기 담아,
변화의 순간, 함께 노래해요! 🎶


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5dda26e and ec6dab0.

📒 Files selected for processing (1)
  • src/test/java/com/example/demo/models/CartTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/com/example/demo/models/CartTest.java

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 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: 20

🧹 Outside diff range and nitpick comments (19)
src/main/java/com/example/demo/models/ProductId.java (1)

6-8: ID 생성 시 유효성 검사 추가 필요

생성된 ID가 null이 아닌지, 형식이 올바른지 확인하는 유효성 검사를 추가하는 것이 좋습니다.

다음과 같이 변경하는 것을 제안합니다:

 public ProductId(){
-    this(new GenerateId().id());
+    String generatedId = new GenerateId().id();
+    if (generatedId == null || generatedId.trim().isEmpty()) {
+        throw new IllegalStateException("상품 ID는 null이거나 비어있을 수 없습니다");
+    }
+    this(generatedId);
 }
src/main/java/com/example/demo/exceptions/ExceedTotalQuantity.java (1)

3-3: 클래스 문서화 및 이름 개선 제안

  1. 이 예외가 언제 발생하는지 설명하는 JavaDoc 문서를 추가하면 좋을 것 같습니다.
  2. 20개 제한이라는 구체적인 내용을 클래스 이름에 반영하는 것을 고려해보세요 (예: ExceedMaximumCartQuantity 또는 ExceedCartItemLimit).
+/**
+ * 장바구니의 총 수량이 20개를 초과할 때 발생하는 예외입니다.
+ */
 public class ExceedTotalQuantity extends RuntimeException {
src/main/java/com/example/demo/models/Product.java (2)

13-15: toString 메서드 개선이 필요합니다.

현재 toString 구현은 최소한의 정보만 제공합니다. 제품 식별을 위해 더 명확한 형식으로 개선하면 좋을 것 같습니다.

다음과 같이 수정하는 것을 추천드립니다:

-    public String toString() {
-        return "{" + productId + "}";
-    }
+    public String toString() {
+        return "Product{productId=" + productId + "}";
+    }

1-3: 클래스 수준의 문서화가 필요합니다.

Product 클래스의 목적과 사용 방법에 대한 JavaDoc 문서화가 누락되어 있습니다. 코드의 가독성과 유지보수성을 위해 문서화를 추가하는 것이 좋습니다.

다음과 같이 수정하는 것을 추천드립니다:

package com.example.demo.models;

+/**
+ * 상품을 나타내는 불변 레코드 클래스입니다.
+ * 장바구니 시스템에서 상품을 식별하고 관리하는데 사용됩니다.
+ */
public record Product (ProductId productId){
src/test/java/com/example/demo/models/ProductIdTest.java (2)

9-13: 테스트 케이스를 더 포괄적으로 작성해주세요

현재 테스트는 ID가 null이 아닌지만 확인하고 있습니다. 다음과 같은 추가 검증이 필요합니다:

  • ID의 형식이 올바른지 확인
  • 여러 ID를 생성했을 때 고유성이 보장되는지 확인

다음과 같이 테스트를 보완하는 것을 추천드립니다:

-    void createProductId(){
-        ProductId id = new ProductId();
-        System.out.println("Generated ID: " + id.id());
-        assertNotNull(id.id(), "ID should not be null");
+    void createProductId() {
+        // 단일 ID 생성 테스트
+        ProductId id = new ProductId();
+        String generatedId = id.id();
+        assertNotNull(generatedId, "ID should not be null");
+        assertTrue(generatedId.matches("^[a-zA-Z0-9]+$"), "ID should be alphanumeric");
+
+        // ID 고유성 테스트
+        ProductId anotherId = new ProductId();
+        assertNotEquals(id.id(), anotherId.id(), "IDs should be unique");

9-9: 테스트 메소드 이름을 더 명확하게 작성해주세요

테스트 메소드 이름은 테스트하는 내용을 명확하게 설명해야 합니다. 현재 이름인 createProductId는 너무 일반적입니다.

다음과 같이 수정하는 것을 추천드립니다:

-    void createProductId(){
+    void shouldGenerateUniqueNonNullProductId(){
src/test/java/com/example/demo/models/CartItemIdTest.java (3)

9-9: 테스트 메서드 이름을 더 구체적으로 지정하세요.

테스트 메서드의 이름이 너무 일반적입니다. 테스트의 목적과 예상 결과를 더 명확하게 표현하는 것이 좋습니다.

다음과 같이 변경하는 것을 제안합니다:

-void createCartItemId() {
+void createCartItemId_ShouldGenerateNonNullId() {

11-11: System.out.println 대신 로깅 프레임워크를 사용하세요.

테스트 코드에서 System.out.println을 사용하는 것은 좋지 않은 방법입니다. 로깅 프레임워크를 사용하거나, 디버그 목적이 아니라면 제거하는 것이 좋습니다.

다음과 같이 변경하는 것을 제안합니다:

-System.out.println("Generated ID: " + id.id());
+// 로깅이 필요한 경우:
+logger.debug("Generated ID: {}", id.id());
+// 또는 완전히 제거

7-14: 테스트 클래스에 문서화를 추가하세요.

테스트 클래스의 목적과 테스트하는 기능에 대한 설명이 없습니다. JavaDoc을 추가하여 문서화하는 것이 좋습니다.

다음과 같이 클래스 수준의 문서화를 추가하는 것을 제안합니다:

+/**
+ * CartItemId 클래스의 ID 생성 기능을 테스트합니다.
+ * 이 테스트 클래스는 ID 생성의 정확성, 고유성 및 형식을 검증합니다.
+ */
class CartItemIdTest {
src/test/java/com/example/demo/models/CartItemTest.java (3)

11-15: 사용되지 않는 필드 제거 필요

cartItemIdproducts 필드가 선언되어 있지만 테스트에서 사용되지 않고 있습니다. 사용하지 않는 필드는 제거하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안합니다:

    private CartItem cartItem;
-   private CartItemId cartItemId;
    private Product product;
    private ProductId productId;
-   private ArrayList<Product> products;

22-23: 지역 변수명 수정 필요

cartItemId 지역 변수가 클래스 필드를 가리고 있습니다. 변수명을 더 명확하게 지정하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안합니다:

-       CartItemId cartItemId = new CartItemId();
+       CartItemId newCartItemId = new CartItemId();
-       cartItem = new CartItem(cartItemId, product, 1);
+       cartItem = new CartItem(newCartItemId, product, 1);

1-31: 테스트 문서화 개선 필요

테스트 클래스에 대한 JavaDoc 문서화가 없습니다. 테스트의 목적과 테스트 대상 클래스의 관계를 명확히 설명하는 문서를 추가하는 것이 좋습니다.

다음과 같은 문서화를 추가하는 것을 제안합니다:

/**
 * CartItem 클래스의 단위 테스트
 * 장바구니 아이템의 수량 관리 기능을 검증합니다.
 */
class CartItemTest {
src/main/java/com/example/demo/models/CartItem.java (1)

27-36: toString 메서드 개선 제안

현재 구현은 올바르지만, 가독성을 위해 String.format을 사용하는 것을 권장드립니다.

 @Override
 public String toString() {
-    return "CartItem{"
-            + "id="
-            + id
-            + ", product="
-            + product
-            + ", quantity="
-            + quantity + "}";
+    return String.format("CartItem{id=%s, product=%s, quantity=%d}", id, product, quantity);
 }
src/test/java/com/example/demo/MongoDbTest.java (2)

23-27: 연결 테스트 보완 필요

단순 null 체크보다 실제 연결 상태를 확인하는 것이 좋습니다.

다음과 같이 개선을 제안합니다:

 @Test
 public void testMongoClientBean() {
-    // MongoClient 빈이 주입되었는지 확인
-    assertThat(mongoClient).isNotNull();
+    assertThat(mongoClient).isNotNull();
+    
+    // 실제 연결 상태 확인
+    Document pingCommand = new Document("ping", 1);
+    Document result = mongoClient.getDatabase("admin")
+        .runCommand(pingCommand);
+    assertThat(result.getDouble("ok")).isEqualTo(1.0);
 }

1-50: 보안 및 아키텍처 개선 필요

MongoDB 연결 보안 및 전반적인 아키텍처 개선이 필요합니다:

  1. 보안 설정 부재
  2. 예외 처리 전략 부재
  3. 테스트 환경 분리 필요

다음 사항들을 고려해주세요:

  1. 테스트용 MongoDB 컨테이너 사용 (TestContainers)
  2. 연결 정보 암호화
  3. 타임아웃 설정
  4. 재시도 정책 설정
  5. 모니터링 추가

예시 구성을 제공해드릴까요?

src/main/java/com/example/demo/models/Cart.java (1)

21-25: 상수 정의 및 메서드 이름 개선이 필요합니다

  1. 장바구니 최대 수량(20)을 상수로 정의하는 것이 좋습니다.
  2. 메서드 이름을 validateQuantityLimit으로 변경하면 의도가 더 명확해질 것 같습니다.
+private static final int MAX_CART_QUANTITY = 20;

-public void checkTotalQuantity(int quantity) {
-    if (this.totalQuantity + quantity > 20) {
+public void validateQuantityLimit(int quantity) {
+    if (this.totalQuantity + quantity > MAX_CART_QUANTITY) {
        throw new ExceedTotalQuantity("장바구니 총 합계는 20을 넘길 수 없습니다.");
    }
}
src/test/java/com/example/demo/models/CartTest.java (3)

22-32: 테스트 데이터의 가독성 개선이 필요합니다

테스트 설정에서 의미 있는 테스트 데이터를 사용하면 테스트의 의도를 더 명확하게 전달할 수 있습니다.

다음과 같이 개선해 보세요:

 @BeforeEach
 void setUp() {
     productId = new ProductId();
-    product = new Product(productId);
+    product = new Product(productId, "테스트 상품", 10000);  // 상품명과 가격 추가
     cartItems = new ArrayList<>();
     cartItemId = new CartItemId();
     cartItem = new CartItem(cartItemId, product, 1);
     cartItems.add(cartItem);
 
-    cart = new Cart(cartItems, 1, product);
+    // 초기 상태를 명확히 주석으로 표현
+    // 장바구니 초기 상태: 상품 1개, 수량 1개
+    cart = new Cart(cartItems, 1, product);

51-62: 수량 제한 테스트 케이스 보완 필요

현재는 20개를 초과하는 한 가지 케이스만 테스트하고 있습니다. 경계값 테스트를 추가하면 좋겠습니다.

다음과 같은 테스트 케이스 추가를 제안합니다:

  • 정확히 20개 추가 시도 (성공 케이스)
  • 19개 보유 상태에서 2개 추가 시도 (실패 케이스)

64-70: 장바구니 비우기 테스트의 사전 조건 보완 필요

빈 장바구니가 아닌 상태에서 시작하는 것이 테스트 의도를 더 명확하게 할 수 있습니다.

테스트 시작 전에 여러 상품을 추가한 후 비우기를 실행하면 좋겠습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

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

📒 Files selected for processing (14)
  • build.gradle.kts (1 hunks)
  • src/main/java/com/example/demo/Application.java (1 hunks)
  • src/main/java/com/example/demo/exceptions/ExceedTotalQuantity.java (1 hunks)
  • src/main/java/com/example/demo/models/Cart.java (1 hunks)
  • src/main/java/com/example/demo/models/CartItem.java (1 hunks)
  • src/main/java/com/example/demo/models/CartItemId.java (1 hunks)
  • src/main/java/com/example/demo/models/GenerateId.java (1 hunks)
  • src/main/java/com/example/demo/models/Product.java (1 hunks)
  • src/main/java/com/example/demo/models/ProductId.java (1 hunks)
  • src/test/java/com/example/demo/MongoDbTest.java (1 hunks)
  • src/test/java/com/example/demo/models/CartItemIdTest.java (1 hunks)
  • src/test/java/com/example/demo/models/CartItemTest.java (1 hunks)
  • src/test/java/com/example/demo/models/CartTest.java (1 hunks)
  • src/test/java/com/example/demo/models/ProductIdTest.java (1 hunks)
🔇 Additional comments (8)
src/main/java/com/example/demo/models/ProductId.java (2)

3-5: 레코드 타입 사용이 적절합니다!

불변성이 보장되어야 하는 ID 값을 위해 record 타입을 사용한 것이 좋은 설계 선택입니다.


7-7: GenerateId 클래스 사용 확인 필요

GenerateId 클래스의 import 문이 누락되어 있으며, 이 클래스가 제대로 구현되어 있는지 확인이 필요합니다.

다음 스크립트로 GenerateId 클래스의 구현을 확인하겠습니다:

✅ Verification successful

GenerateId 클래스가 정상적으로 구현되어 있음을 확인했습니다

GenerateId 클래스는 src/main/java/com/example/demo/models/GenerateId.java에 올바르게 구현되어 있으며:

  • 같은 패키지(com.example.demo.models)에 위치하여 별도의 import가 필요하지 않습니다
  • id() 메서드가 구현되어 있고 날짜와 UUID를 조합하여 고유 ID를 생성합니다
  • 테스트 코드에서도 정상적으로 사용되고 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# GenerateId 클래스의 구현 확인
rg -l "class GenerateId" 

# id() 메서드 구현 확인
ast-grep --pattern 'class GenerateId {
  $$$
  id() {
    $$$
  }
  $$$
}'

Length of output: 103


Script:

#!/bin/bash
# GenerateId 클래스 파일 검색 (대소문자 구분 없이)
fd -i generateid

# GenerateId 관련 import 문 검색
rg "import.*GenerateId"

# ProductId.java 파일의 전체 내용 확인
fd -e java -x cat {} ProductId.java

Length of output: 15356

src/main/java/com/example/demo/models/CartItemId.java (1)

3-5: 레코드 사용이 적절합니다!

불변성이 보장되어야 하는 ID를 위해 record를 사용한 것이 좋은 선택입니다. equals, hashCode, toString 메서드가 자동으로 생성되어 ID 비교 및 로깅에 유용할 것입니다.

src/main/java/com/example/demo/exceptions/ExceedTotalQuantity.java (1)

3-7: 기본 구현이 올바르게 되어 있습니다!

RuntimeException을 상속받아 비즈니스 로직 예외를 적절히 처리할 수 있도록 구현되었습니다.

src/main/java/com/example/demo/Application.java (1)

3-4: MongoDB 관련 import 구문이 올바르게 추가되었습니다.

필요한 MongoDB 클라이언트 관련 클래스들이 적절하게 import 되었습니다.

Also applies to: 7-7

src/main/java/com/example/demo/models/GenerateId.java (2)

7-14: 레코드 클래스의 가시성 및 불변성이 적절합니다.

레코드를 사용하여 ID를 불변 객체로 만든 것은 좋은 설계 선택입니다.


16-16: IdGenerator 클래스의 가시성 검토가 필요합니다.

IdGenerator 클래스가 package-private 가시성을 가지고 있습니다. 이 클래스가 다른 패키지에서 사용될 필요가 없다면 현재 가시성이 적절하지만, 그렇지 않다면 public으로 변경을 고려해보세요.

다음 스크립트로 다른 패키지에서의 사용 여부를 확인해보겠습니다:

✅ Verification successful

IdGenerator 클래스의 현재 가시성이 적절합니다.

IdGenerator 클래스는 GenerateId 레코드 내부에서만 사용되며, 같은 패키지 내에서만 접근이 필요합니다. 현재의 package-private 가시성이 캡슐화 원칙에 잘 부합하므로 변경이 필요하지 않습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 다른 패키지에서 IdGenerator를 사용하려는 시도가 있는지 확인
rg "IdGenerator" --type java

Length of output: 202


Script:

#!/bin/bash
# GenerateId.java 파일의 전체 내용을 확인하여 IdGenerator의 사용 맥락을 파악
cat src/main/java/com/example/demo/models/GenerateId.java

Length of output: 693

src/main/java/com/example/demo/models/CartItem.java (1)

19-25: Product 객체의 불변성 보장 필요

만약 Product 클래스가 가변 객체라면, getter에서 방어적 복사본을 반환하는 것이 안전합니다.

Comment on lines +6 to +8
public CartItemId(){
this(new GenerateId().id());
}
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

🛠️ Refactor suggestion

ID 생성 로직 검증 완료 및 개선 권장

GenerateId와 IdGenerator 클래스의 구현을 확인한 결과, 다음과 같은 개선이 필요합니다:

  1. IdGenerator는 현재 시간(yyyyMMddHHmm)과 UUID 조합으로 ID를 생성하고 있어 기본적으로 null이 반환될 가능성은 낮습니다. 하지만 견고성을 위해 검증 로직 추가가 권장됩니다.
  2. 원래 제안된 수정사항이 여전히 유효합니다.

수정 제안:

public CartItemId(){
    String generatedId = new GenerateId().id();
    if (generatedId == null || generatedId.trim().isEmpty()) {
        throw new IllegalStateException("장바구니 아이템 ID가 올바르게 생성되지 않았습니다.");
    }
    this(generatedId);
}
🔗 Analysis chain

GenerateId 클래스 사용 및 유효성 검사 확인이 필요합니다.

다음 사항들을 확인해 주시기 바랍니다:

  1. GenerateId 클래스가 올바르게 구현되어 있는지 확인
  2. 생성된 ID가 null이 아님을 보장하는 검증 로직 추가 필요

다음과 같이 수정하는 것을 제안드립니다:

 public CartItemId(){
-    this(new GenerateId().id());
+    String generatedId = new GenerateId().id();
+    if (generatedId == null || generatedId.trim().isEmpty()) {
+        throw new IllegalStateException("장바구니 아이템 ID가 올바르게 생성되지 않았습니다.");
+    }
+    this(generatedId);
 }

GenerateId 클래스 구현을 확인하기 위해 다음 스크립트를 실행합니다:


Let me try a different search pattern to locate the GenerateId implementation.


Let me check the implementation of IdGenerator to complete the verification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# GenerateId 클래스 구현 확인
echo "Searching for GenerateId class implementation..."
rg -l "class GenerateId"

# ID 생성 메서드 구현 확인
echo "Checking ID generation implementation..."
ast-grep --pattern 'class GenerateId {
  $$$
  $_ id() {
    $$$
  }
  $$$
}'

Length of output: 304


Script:

#!/bin/bash
# Search for GenerateId class with broader pattern
echo "Searching for GenerateId class with broader pattern..."
rg -A 5 "GenerateId"

# Search for files containing 'id' method
echo "Searching for files with id method..."
rg -A 3 "id\(\)"

Length of output: 2460


Script:

#!/bin/bash
# Check IdGenerator implementation
echo "Checking IdGenerator implementation..."
rg -A 10 "class IdGenerator"

# Check if there are any existing null checks
echo "Checking for null checks in related files..."
rg -A 3 "null|isEmpty|isBlank" src/main/java/com/example/demo/models/

Length of output: 1250

Comment on lines 5 to 7
public Product(ProductId productId) {
this.productId = productId;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

불필요한 생성자 구현이 있습니다.

Record 클래스는 자동으로 canonical 생성자를 생성하므로, 명시적인 생성자 구현이 불필요합니다. 현재 구현된 생성자는 기본 생성자와 동일한 동작을 수행합니다.

다음과 같이 수정하는 것을 추천드립니다:

-    public Product(ProductId productId) {
-        this.productId = productId;
-    }

Comment on lines 9 to 11
public ProductId getProductId() {
return productId;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

불필요한 getter 메서드가 있습니다.

Record 클래스는 자동으로 각 필드에 대한 접근자 메서드를 생성합니다. productId()라는 이름으로 자동 생성되므로, 명시적인 getter 구현은 불필요합니다.

다음과 같이 수정하는 것을 추천드립니다:

-    public ProductId getProductId() {
-        return productId;
-    }

Committable suggestion skipped: line range outside the PR's diff.

@Test
void createProductId(){
ProductId id = new ProductId();
System.out.println("Generated ID: " + id.id());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

System.out.println 대신 로깅 프레임워크를 사용하세요

테스트 코드에서 System.out.println을 사용하는 것은 좋지 않은 관행입니다. 대신 SLF4J나 Log4j와 같은 로깅 프레임워크를 사용하는 것이 좋습니다.

다음과 같이 수정하는 것을 추천드립니다:

-        System.out.println("Generated ID: " + id.id());
+        private static final Logger logger = LoggerFactory.getLogger(ProductIdTest.class);
+        logger.debug("Generated ID: {}", id.id());

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +8 to +13
@Test
void createCartItemId(){
CartItemId id = new CartItemId();
System.out.println("Generated ID: " + id.id());
assertNotNull(id.id(), "ID should not be null");
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

테스트 케이스 보완이 필요합니다.

현재 테스트는 ID가 null이 아닌지만 확인하고 있습니다. ID의 고유성이나 형식에 대한 추가 검증이 필요할 수 있습니다.

다음과 같은 추가 테스트 케이스를 제안합니다:

@Test
void createMultipleCartItemIds_ShouldGenerateUniqueIds() {
    CartItemId id1 = new CartItemId();
    CartItemId id2 = new CartItemId();
    
    assertNotEquals(id1.id(), id2.id(), "Generated IDs should be unique");
}

@Test
void generatedId_ShouldFollowExpectedFormat() {
    CartItemId id = new CartItemId();
    String generatedId = id.id();
    
    // ID 형식이 예상된 패턴을 따르는지 확인
    assertTrue(generatedId.matches("^[a-zA-Z0-9-]+$"), "ID should match expected format");
}

Comment on lines 8 to 19
public class Cart {

private ArrayList<CartItem> cartItems;
private int totalQuantity;
private final Product product;

public Cart(ArrayList<CartItem> cartItems, int totalQuantity,
Product product) {
this.cartItems = cartItems;
this.totalQuantity = totalQuantity;
this.product = product;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

클래스 구조 개선이 필요합니다

다음과 같은 개선사항을 제안드립니다:

  1. cartItems를 불변 리스트로 만들어 스레드 안전성을 향상시킬 수 있습니다.
  2. Product product 필드가 각 CartItem이 자체 Product를 가지고 있는데 추가로 존재하는 이유가 불명확합니다.
  3. 생성자에서 ArrayList를 직접 받는 대신 초기화하는 것이 안전합니다.
-private ArrayList<CartItem> cartItems;
-private int totalQuantity;
-private final Product product;
+private final List<CartItem> cartItems;
+private int totalQuantity;

-public Cart(ArrayList<CartItem> cartItems, int totalQuantity,
-        Product product) {
+public Cart() {
-    this.cartItems = cartItems;
-    this.totalQuantity = totalQuantity;
-    this.product = product;
+    this.cartItems = new ArrayList<>();
+    this.totalQuantity = 0;
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class Cart {
private ArrayList<CartItem> cartItems;
private int totalQuantity;
private final Product product;
public Cart(ArrayList<CartItem> cartItems, int totalQuantity,
Product product) {
this.cartItems = cartItems;
this.totalQuantity = totalQuantity;
this.product = product;
}
public class Cart {
private final List<CartItem> cartItems;
private int totalQuantity;
public Cart() {
this.cartItems = new ArrayList<>();
this.totalQuantity = 0;
}

Comment on lines +27 to +41
public void addCartItem(ProductId productId, int quantity) {

checkTotalQuantity(quantity);

Optional<CartItem> existingCartItem = findCartItem(productId);
if (existingCartItem.isPresent()) {
CartItem cartItem = existingCartItem.get();
cartItem.addQuantity(quantity);
} else {
addNewCartItem(productId, quantity);
}

this.totalQuantity += quantity;

}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

수량 검증 및 동시성 처리가 필요합니다

  1. 음수 수량에 대한 검증이 없습니다.
  2. totalQuantity 업데이트 시 동시성 문제가 발생할 수 있습니다.
  3. 메서드가 다소 긴 편이니 책임을 분리하면 좋을 것 같습니다.
public void addCartItem(ProductId productId, int quantity) {
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("수량은 0보다 커야 합니다.");
+    }

-    checkTotalQuantity(quantity);
+    validateQuantityLimit(quantity);

    Optional<CartItem> existingCartItem = findCartItem(productId);
-    if (existingCartItem.isPresent()) {
-        CartItem cartItem = existingCartItem.get();
-        cartItem.addQuantity(quantity);
-    } else {
-        addNewCartItem(productId, quantity);
-    }
+    synchronized(this) {
+        if (existingCartItem.isPresent()) {
+            CartItem cartItem = existingCartItem.get();
+            cartItem.addQuantity(quantity);
+        } else {
+            addNewCartItem(productId, quantity);
+        }
+        this.totalQuantity += quantity;
+    }
-    this.totalQuantity += quantity;
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void addCartItem(ProductId productId, int quantity) {
checkTotalQuantity(quantity);
Optional<CartItem> existingCartItem = findCartItem(productId);
if (existingCartItem.isPresent()) {
CartItem cartItem = existingCartItem.get();
cartItem.addQuantity(quantity);
} else {
addNewCartItem(productId, quantity);
}
this.totalQuantity += quantity;
}
public void addCartItem(ProductId productId, int quantity) {
if (quantity <= 0) {
throw new IllegalArgumentException("수량은 0보다 커야 합니다.");
}
validateQuantityLimit(quantity);
Optional<CartItem> existingCartItem = findCartItem(productId);
synchronized(this) {
if (existingCartItem.isPresent()) {
CartItem cartItem = existingCartItem.get();
cartItem.addQuantity(quantity);
} else {
addNewCartItem(productId, quantity);
}
this.totalQuantity += quantity;
}
}

Comment on lines 43 to 68
private void addNewCartItem(ProductId productId, int quantity) {
CartItemId cartItemId = new CartItemId();
Product product = new Product(productId);
CartItem newCartItem = new CartItem(cartItemId, product, quantity);
cartItems.add(newCartItem);
}

private Optional<CartItem> findCartItem(ProductId productId) {
return cartItems.stream()
.filter(cartItem ->
cartItem.getProduct().getProductId().equals(productId))
.findFirst();
}

public List<CartItem> getCartList() {
return cartItems;
}

public void madeCartZero() {
this.totalQuantity = 0;
this.cartItems = new ArrayList<CartItem>();
}

public int getTotalQuantity() {
return totalQuantity;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

메서드 이름 및 Null 처리 개선이 필요합니다

  1. madeCartZeroclear 또는 reset으로 변경하는 것이 관례에 맞습니다.
  2. addNewCartItem에서 Product 생성 시 null 체크가 필요합니다.
  3. findCartItem의 스트림 체이닝이 가독성을 위해 개선이 필요합니다.
private void addNewCartItem(ProductId productId, int quantity) {
+    if (productId == null) {
+        throw new IllegalArgumentException("상품 ID는 null일 수 없습니다.");
+    }
    CartItemId cartItemId = new CartItemId();
    Product product = new Product(productId);
    CartItem newCartItem = new CartItem(cartItemId, product, quantity);
    cartItems.add(newCartItem);
}

-public void madeCartZero() {
+public void clear() {
    this.totalQuantity = 0;
    this.cartItems = new ArrayList<CartItem>();
}

private Optional<CartItem> findCartItem(ProductId productId) {
    return cartItems.stream()
-            .filter(cartItem ->
-                    cartItem.getProduct().getProductId().equals(productId))
+            .filter(cartItem -> {
+                Product product = cartItem.getProduct();
+                return product != null && 
+                    product.getProductId().equals(productId);
+            })
            .findFirst();
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void addNewCartItem(ProductId productId, int quantity) {
CartItemId cartItemId = new CartItemId();
Product product = new Product(productId);
CartItem newCartItem = new CartItem(cartItemId, product, quantity);
cartItems.add(newCartItem);
}
private Optional<CartItem> findCartItem(ProductId productId) {
return cartItems.stream()
.filter(cartItem ->
cartItem.getProduct().getProductId().equals(productId))
.findFirst();
}
public List<CartItem> getCartList() {
return cartItems;
}
public void madeCartZero() {
this.totalQuantity = 0;
this.cartItems = new ArrayList<CartItem>();
}
public int getTotalQuantity() {
return totalQuantity;
}
private void addNewCartItem(ProductId productId, int quantity) {
if (productId == null) {
throw new IllegalArgumentException("상품 ID는 null일 수 없습니다.");
}
CartItemId cartItemId = new CartItemId();
Product product = new Product(productId);
CartItem newCartItem = new CartItem(cartItemId, product, quantity);
cartItems.add(newCartItem);
}
private Optional<CartItem> findCartItem(ProductId productId) {
return cartItems.stream()
.filter(cartItem -> {
Product product = cartItem.getProduct();
return product != null &&
product.getProductId().equals(productId);
})
.findFirst();
}
public List<CartItem> getCartList() {
return cartItems;
}
public void clear() {
this.totalQuantity = 0;
this.cartItems = new ArrayList<CartItem>();
}
public int getTotalQuantity() {
return totalQuantity;
}

Comment on lines 34 to 40
@DisplayName("기존의 상품을 추가할 경우")
@Test
void addCartItem() {
cart.addCartItem(productId, 1);
assertEquals(2, cart.getTotalQuantity());
assertEquals(1, cartItems.size());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

기존 상품 추가 테스트 케이스 보완 필요

현재 테스트는 기본적인 케이스만 다루고 있습니다. 다음과 같은 엣지 케이스도 검증이 필요합니다:

  • 음수 수량 추가 시도
  • 0개 수량 추가 시도

Comment on lines 72 to 80
@DisplayName("장바구니 목록 보기")
@Test
void getCartList() {
assertTrue(cart.getCartList().toString().contains("quantity=1"));
assertTrue(cart.getCartList().toString()
.contains("product={" + productId + "}"));
assertTrue(cart.getCartList().toString()
.contains("id=" + cartItemId));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

장바구니 목록 검증 방식 개선 필요

현재 toString() 결과를 검증하는 방식은 구현이 변경되면 테스트가 깨질 수 있습니다.

다음과 같이 개선해 보세요:

 @Test
 void getCartList() {
-    assertTrue(cart.getCartList().toString().contains("quantity=1"));
-    assertTrue(cart.getCartList().toString()
-            .contains("product={" + productId + "}"));
-    assertTrue(cart.getCartList().toString()
-            .contains("id=" + cartItemId));
+    CartItem firstItem = cart.getCartList().get(0);
+    assertEquals(1, firstItem.getQuantity());
+    assertEquals(productId, firstItem.getProduct().getId());
+    assertEquals(cartItemId, firstItem.getId());
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@DisplayName("장바구니 목록 보기")
@Test
void getCartList() {
assertTrue(cart.getCartList().toString().contains("quantity=1"));
assertTrue(cart.getCartList().toString()
.contains("product={" + productId + "}"));
assertTrue(cart.getCartList().toString()
.contains("id=" + cartItemId));
}
@DisplayName("장바구니 목록 보기")
@Test
void getCartList() {
CartItem firstItem = cart.getCartList().get(0);
assertEquals(1, firstItem.getQuantity());
assertEquals(productId, firstItem.getProduct().getId());
assertEquals(cartItemId, firstItem.getId());
}

Record 에서는 getter는 불필요함
또한 자동으로 생성자를 생성해주기 때문에 생성자 명시도 불필요함
ID의 고유성이나 형식에 대한 추가 검증 추가
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: 2

🧹 Outside diff range and nitpick comments (4)
src/test/java/com/example/demo/models/ProductIdTest.java (2)

9-13: 테스트 케이스를 보강해 주세요

현재 테스트는 null 체크만 수행하고 있습니다. 다음과 같은 추가 검증을 고려해 보세요:

  • ID 형식 검증
  • ID 길이 검증
  • 특수 문자 포함 여부 검증

15-20: 고유성 테스트를 강화해 주세요

두 개의 ID만 비교하는 것은 충분하지 않을 수 있습니다. 다음을 고려해 보세요:

  • 더 많은 수의 ID 생성 및 비교 (예: 100개)
  • 동시성 상황에서의 고유성 테스트
src/test/java/com/example/demo/models/CartItemTest.java (1)

15-15: 사용되지 않는 필드 제거 필요

products ArrayList가 선언되어 있지만 테스트 코드 어디에서도 사용되지 않습니다. 불필요한 코드는 제거하는 것이 좋습니다.

-    private ArrayList<Product> products;
src/main/java/com/example/demo/models/CartItem.java (1)

41-63: 비즈니스 키 전략에 대한 설명 필요

equals와 hashCode가 id 필드만을 사용하는 것은 적절하나, 이러한 설계 결정에 대한 설명이 문서화되면 좋겠습니다.

 public class CartItem {
+    /**
+     * CartItem의 동일성은 id 필드로만 판단됩니다.
+     * 이는 동일한 상품이라도 장바구니에 따로 담긴 경우 서로 다른 항목으로 처리하기 위함입니다.
+     */
     private final CartItemId id;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 84d2fa5 and 741c0cf.

📒 Files selected for processing (7)
  • src/main/java/com/example/demo/models/Cart.java (1 hunks)
  • src/main/java/com/example/demo/models/CartItem.java (1 hunks)
  • src/main/java/com/example/demo/models/Product.java (1 hunks)
  • src/main/java/com/example/demo/models/ProductId.java (1 hunks)
  • src/test/java/com/example/demo/models/CartItemTest.java (1 hunks)
  • src/test/java/com/example/demo/models/CartTest.java (1 hunks)
  • src/test/java/com/example/demo/models/ProductIdTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main/java/com/example/demo/models/Cart.java
  • src/main/java/com/example/demo/models/Product.java
  • src/main/java/com/example/demo/models/ProductId.java
  • src/test/java/com/example/demo/models/CartTest.java
🔇 Additional comments (6)
src/test/java/com/example/demo/models/ProductIdTest.java (1)

11-11: System.out.println 대신 로깅 프레임워크를 사용하세요

테스트 코드에서 System.out.println 사용은 피해야 합니다. 대신 SLF4J나 Log4j와 같은 로깅 프레임워크를 사용하세요.

src/test/java/com/example/demo/models/CartItemTest.java (1)

32-46: 테스트 케이스 개선이 잘 이루어졌습니다! 👍

이전 리뷰에서 제안된 테스트 케이스들이 모두 구현되었습니다:

  • 양수 추가 시나리오
  • 음수 추가 시나리오
  • 0 추가 시나리오

각 테스트의 의도가 명확하게 드러나는 이름을 사용한 것도 좋습니다.

src/main/java/com/example/demo/models/CartItem.java (4)

11-24: 생성자 구현이 적절합니다

null 체크와 수량 검증이 잘 구현되어 있으며, 예외 메시지도 명확합니다.


5-9: 🛠️ Refactor suggestion

필드 유효성 검증 어노테이션 추가 필요

이전 리뷰에서 지적된 바와 같이, 필드 레벨의 유효성 검증이 여전히 누락되어 있습니다.

+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;

 public class CartItem {
-    private final CartItemId id;
-    private final Product product;
-    private int quantity;
+    @NotNull
+    private final CartItemId id;
+    @NotNull
+    private final Product product;
+    @Min(value = 1, message = "수량은 1 이상이어야 합니다")
+    private int quantity;

26-31: ⚠️ Potential issue

수량 관리 로직 보완 필요

현재 구현에서 다음 사항들이 보완되어야 합니다:

  1. 최대 주문 가능 수량 제한이 없습니다
  2. 0을 추가하는 것이 허용됩니다 (에러 메시지는 0 이상이라고 되어있으나, 비즈니스 로직상 양수여야 합니다)
 public void addQuantity(int quantity) {
-    if (quantity < 0) {
-        throw new IllegalArgumentException("추가할 수량은 0 이상이어야 합니다");
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("추가할 수량은 양수여야 합니다");
+    }
+    if (this.quantity + quantity > 9999) {
+        throw new IllegalArgumentException("최대 주문 가능 수량(9999)을 초과할 수 없습니다");
     }
     this.quantity += quantity;
 }

Likely invalid or redundant comment.


33-39: id 필드의 getter 메서드 필요 여부 확인

id 필드에 대한 getter가 없습니다. 영속성 계층이나 외부 시스템과의 통합에서 필요할 수 있으니 검토가 필요합니다.

Comment on lines +27 to +28
// ID 형식이 예상된 패턴을 따르는지 확인
assertTrue(generatedId.matches("^[a-zA-Z0-9-]+$"), "ID should match expected format");
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

정규식 패턴과 주석을 개선해 주세요

개선이 필요한 부분들:

  1. 주석을 영어로 작성하여 일관성을 유지해 주세요.
  2. 정규식 패턴이 너무 광범위합니다. ID 형식에 대한 더 구체적인 제약을 추가하는 것이 좋습니다.
  3. 허용되는 ID 형식에 대한 명확한 문서화가 필요합니다.

다음과 같이 수정하는 것을 제안드립니다:

-        // ID 형식이 예상된 패턴을 따르는지 확인
-        assertTrue(generatedId.matches("^[a-zA-Z0-9-]+$"), "ID should match expected format");
+        // Verify that the ID follows the expected format: 
+        // - Must start with a letter
+        // - Can contain letters, numbers, and hyphens
+        // - Must be between 8 and 36 characters
+        assertTrue(generatedId.matches("^[a-zA-Z][a-zA-Z0-9-]{7,35}$"), 
+            "ID must start with a letter and be 8-36 characters long");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// ID 형식이 예상된 패턴을 따르는지 확인
assertTrue(generatedId.matches("^[a-zA-Z0-9-]+$"), "ID should match expected format");
// Verify that the ID follows the expected format:
// - Must start with a letter
// - Can contain letters, numbers, and hyphens
// - Must be between 8 and 36 characters
assertTrue(generatedId.matches("^[a-zA-Z][a-zA-Z0-9-]{7,35}$"),
"ID must start with a letter and be 8-36 characters long");

Comment on lines +26 to +30
@Test
void addQuantity() {
cartItem.addQuantity(1);
assertEquals(2, cartItem.getQuantity());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

중복된 테스트 케이스 통합 필요

addQuantity() 테스트와 addQuantity_WhenAddingPositiveNumber_ShouldIncreaseQuantity() 테스트가 동일한 시나리오를 검증하고 있습니다. 명확한 이름을 가진 후자의 테스트만 유지하는 것이 좋습니다.

-    @Test
-    void addQuantity() {
-        cartItem.addQuantity(1);
-        assertEquals(2, cartItem.getQuantity());
-    }

Also applies to: 32-35

Copy link
Member

Choose a reason for hiding this comment

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

ID를 확인하는 테스트는 크게 메리트가 없습니다. 비즈니스 로직에 훨씬 많은 노력을 기울이세요.

Comment on lines 56 to 58
assertEquals(
"장바구니 총 합계는 20을 넘길 수 없습니다."
, exception.getMessage());
Copy link
Member

Choose a reason for hiding this comment

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

텍스트를 확인하면 변경에 취약합니다. 위에서 이미 assertThrows를 했고, 그걸로 충분합니다.

Comment on lines 71 to 76
void getCartList() {
System.out.println(cart.getCartList().toString());
assertTrue(cart.getCartList().toString().contains("quantity=1"));
assertTrue(cart.getCartList().toString()
.contains("product={" + productId + "}"));
}
Copy link
Member

Choose a reason for hiding this comment

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

이건 사실상 toSting을 테스트하는 겁니다. toString은 필요에 의해 아무렇게나 변경할 수 있어야 하고, 이 테스트는 이런 변경에 매우 취약합니다.

void setUp() {
productId = new ProductId();
cart = new Cart();
cart.addCartItem(productId, 1);
Copy link
Member

Choose a reason for hiding this comment

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

여기서 상품을 추가할 이유가 없습니다. 아래에 있는 테스트 코드를 읽는 사람은 이 전제 때문에 매우 혼란스러워 햘 겁니다.

Comment on lines 38 to 46
@DisplayName("새로운 상품을 추가할 경우")
@Test
void addNewCartItem() {
ProductId newProductId = new ProductId();
cart.addCartItem(newProductId, 1);

assertEquals(2, cart.getTotalQuantity());
assertEquals(2, cart.getCartList().size());
}
Copy link
Member

Choose a reason for hiding this comment

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

새로우 상품을 추가하는 경우의 시나리오를 늘려서 신뢰할 수 있게 하세요. 지금은 setUp에서 강력한 제약을 걸고 있어서, 이 코드를 총체적으로 이해하는데 어려움을 겪게 됩니다.

assertThrows로 이미 충분
-> 변경메세지까지 확인하면 테스트코드의 유연성 좋지 않음
@ramyo564
Copy link
Author

ramyo564 commented Dec 2, 2024

  1. toString 테스트가 아닌 값이 제대로 목록에 들어오는지 확인하는 걸로 변경
  2. setUp 제거 -> 각각 테스트 코드에 추가해 가독성 개선
  3. 좀 더 명확히 테스트 코드를 이해할 수 있게 given / when / then 주석처리 추가

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