Skip to content

[3주차] Cart App #2#7

Open
moonnahye wants to merge 11 commits intodal-lab:mainfrom
moonnahye:cart-domain-model
Open

[3주차] Cart App #2#7
moonnahye wants to merge 11 commits intodal-lab:mainfrom
moonnahye:cart-domain-model

Conversation

@moonnahye
Copy link

@moonnahye moonnahye commented Feb 23, 2025

Summary by CodeRabbit

  • 새로운 기능
    • 장바구니 조회 시 상세한 상품 정보와 총 가격이 제공되어 구매 내역을 한눈에 확인할 수 있습니다.
    • 상품 추가 기능에 유효성 검사가 도입되어, 선택한 상품의 수량이 효율적으로 관리됩니다.
    • 전반적인 데이터 처리 및 상품 관리 기능이 강화되어 보다 안정적인 쇼핑 경험을 지원합니다.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2025

Walkthrough

이번 변경 사항은 MongoDB 연동을 위한 의존성 추가와 함께 Spring Boot 애플리케이션에 MongoClient 및 MongoDatabase 빈을 등록하는 작업을 포함합니다. 또한, 카트와 관련된 도메인, 서비스, 컨트롤러, DTO, 저장소(repository) 클래스가 새롭게 추가되거나 수정되었으며, 각 기능에 대한 단위 테스트도 함께 도입되었습니다.

Changes

파일 변경 요약
build.gradle.kts MongoDB 드라이버(core, sync) 의존성 추가
.../Application.java MongoClient와 MongoDatabase 빈 생성 메소드 추가
.../application/CartService.java 카트 조회 및 제품 추가 기능을 제공하는 서비스 클래스 추가 (CartRepository, ProductRepository 연동)
.../controllers/CartController.java 카트 상세 조회 리턴 타입을 DTO로 변경하고, DTO 매핑 로직(mapToDto) 추가
.../controllers/LineItemController.java CartService 주입 및 제품 추가 메소드 수정 (AddProductToCartDto 요청 바디 처리)
.../controllers/dtos/AddProductToCartDto.java 제품 추가를 위한 DTO(record) 추가 (유효성 검증 포함)
.../controllers/dtos/CartDto.java 카트 상세 정보를 위한 DTO(record) 및 내부 LineItemDto 기록 추가
.../infrastructure/CartRepository.java 카트 조회 및 저장을 위한 저장소 클래스 추가
.../infrastructure/LineItemRepository.java MongoDB 기반의 라인 아이템 CRUD 기능을 제공하는 저장소 클래스 추가
.../infrastructure/ProductRepository.java 제품 조회를 위한 저장소 클래스 추가 (MongoDB 연동)
.../model/Cart.java 카트 도메인 클래스 추가, 제품 추가 및 총 가격 계산 로직 포함
.../model/LineItem.java 라인 아이템 도메인 클래스 추가, 수량 관리 및 총 가격 계산 기능 포함
.../model/Product.java 제품 도메인 클래스 추가 (id, name, price 필드)
.../MongoTest.java MongoDB 연결 및 제품 컬렉션의 내용을 검증하는 테스트 클래스 추가
.../application/CartServiceTest.java CartService의 기능(총 가격, 제품 추가 등)을 검증하는 단위 테스트 추가
.../controllers/CartControllerTest.java CartController의 DTO 매핑 및 응답 검증을 위한 테스트 업데이트 (CartService 모킹 포함)
.../controllers/LineItemControllerTest.java 잘못된 입력에 대한 유효성 검증 테스트(빈 제품ID, 0 수량 등) 추가, CartService 모킹 포함
.../model/CartTest.java 카트의 총 가격 계산 및 제품 관리 기능에 대한 단위 테스트 추가
.../model/LineItemTest.java 라인 아이템의 수량 추가 및 제품 설정, 총 가격 계산 기능에 대한 단위 테스트 추가

Sequence Diagram(s)

sequenceDiagram
    participant U as 사용자
    participant LIC as LineItemController
    participant CS as CartService
    participant PR as ProductRepository
    participant CR as CartRepository

    U->>LIC: POST /cart/line-items (AddProductToCartDto)
    LIC->>CS: addProduct(productId, quantity)
    CS->>PR: find(productId)
    PR-->>CS: Product 정보 반환
    CS->>CR: getCart()로 기존 카트 조회
    CS->>CR: save(cart)로 카트 저장
    CS-->>LIC: 처리 결과 반환
    LIC-->>U: HTTP 200 응답 전송
Loading

Poem

나는 작은 토끼, 코드 숲 속을 달리네
MongoDB의 비밀, 내 발자국에 스며들어
서비스, 컨트롤러 춤을 추며 연결되고
테스트의 별빛 아래 버그는 사라지네
새 기능의 기쁨, 코딩의 향연 속에 봄이 오네 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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. (Beta)
  • @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: 13

🧹 Nitpick comments (11)
src/main/java/com/example/demo/controllers/dtos/CartDto.java (1)

1-19: DTO 구조가 간결하고 일관적입니다.
CartDto와 내부 LineItemDto를 통해 장바구니와 해당 품목 정보를 명확하게 표현하고 있습니다.
금액 정보를 다룰 때는 필요에 따라 BigDecimal 등을 고려해 정밀도 손실을 방지하는 방법도 검토할 수 있습니다.

src/main/java/com/example/demo/infrastructure/CartRepository.java (1)

18-21: find 메서드에 예외 처리를 추가하세요.

데이터베이스 조회 시 발생할 수 있는 예외에 대한 처리가 필요합니다.

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

public Cart find() {
+    try {
        List<LineItem> lineItems = lineItemRepository.findAll();
        return new Cart(lineItems);
+    } catch (Exception e) {
+        throw new RuntimeException("장바구니 조회 중 오류가 발생했습니다.", e);
+    }
}
src/test/java/com/example/demo/model/LineItemTest.java (2)

17-29: 테스트 케이스 보완 필요

현재 구현된 addQuantity 테스트는 기본적인 시나리오만 검증하고 있습니다. 다음과 같은 추가 테스트 케이스를 고려해 주세요:

  • 음수 수량 추가 시의 동작
  • 최대 허용 수량 초과 시의 동작
  • 0 수량 추가 시의 동작

31-42: 상품 설정 관련 예외 케이스 테스트 필요

setProductAndGetTotalPrice 테스트에 다음 시나리오를 추가하는 것이 좋습니다:

  • null 상품 설정 시의 동작
  • 상품 정보가 없는 경우의 동작
  • 가격이 0인 상품의 총액 계산
src/main/java/com/example/demo/model/Cart.java (1)

38-43: Null 반환 대신 Optional 사용 권장

getLineItem 메서드에서 null을 반환하는 대신 Optional을 사용하는 것이 더 안전한 방식입니다.

-public LineItem getLineItem(Product product) {
+public Optional<LineItem> getLineItem(Product product) {
     return lineItems.stream()
             .filter(i -> i.getProductId().equals(product.getId()))
-            .findFirst()
-            .orElse(null);
+            .findFirst();
}
src/main/java/com/example/demo/application/CartService.java (1)

46-54: 메서드 문서화가 필요합니다.

공개 메서드에 대한 JavaDoc 문서화를 추가하면 좋겠습니다.

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

+    /**
+     * 장바구니에 상품을 추가합니다.
+     * @param productId 추가할 상품의 ID
+     * @param quantity 추가할 상품의 수량
+     * @throws ProductNotFoundException 상품을 찾을 수 없는 경우
+     */
     public void addProduct(String productId, int quantity) {
src/test/java/com/example/demo/application/CartServiceTest.java (1)

53-63: 테스트 케이스 보완이 필요합니다.

현재는 기본적인 상품 추가 케이스만 테스트하고 있습니다. 다음과 같은 추가 테스트 케이스가 필요합니다:

  • 존재하지 않는 상품 ID로 추가 시도
  • 음수 수량으로 추가 시도
  • 재고보다 많은 수량으로 추가 시도
src/test/java/com/example/demo/controllers/LineItemControllerTest.java (2)

39-53: 유효성 검사 테스트가 잘 구현되었습니다.

빈 productId에 대한 검증 테스트가 적절히 구현되어 있습니다. 다만, 다음 사항을 고려해보시기 바랍니다:

  • null 값에 대한 테스트 케이스 추가
  • 최대 길이 제한에 대한 테스트 케이스 추가

55-69: 수량 검증 테스트가 잘 구현되었습니다.

수량이 0일 때의 검증이 잘 구현되어 있습니다. 추가로 다음 테스트 케이스도 고려해보시면 좋겠습니다:

  • 음수 수량에 대한 테스트
  • 최대 허용 수량 초과에 대한 테스트
src/test/java/com/example/demo/model/CartTest.java (1)

107-111: 헬퍼 메서드 구현이 적절합니다만, 개선의 여지가 있습니다.

createLineItem 메서드가 테스트 코드 중복을 잘 제거하고 있습니다. 다만 다음과 같은 개선을 고려해보세요:

  • 빌더 패턴 적용
  • 메서드 접근 제어자를 private static으로 변경
-    private LineItem createLineItem(Product product, int quantity) {
+    private static LineItem createLineItem(Product product, int quantity) {
         LineItem lineItem = new LineItem(product.getId(), quantity);
         lineItem.setProduct(product);
         return lineItem;
     }
build.gradle.kts (1)

22-23: MongoDB 드라이버 의존성이 추가되었습니다.

MongoDB 드라이버 의존성이 잘 추가되었습니다만, 다음 사항들을 고려해보시기 바랍니다:

  • 버전을 변수로 추출하여 관리
  • Spring Data MongoDB 사용 고려
+    val mongoDriverVersion = "5.3.1"
-    implementation("org.mongodb:mongodb-driver-core:5.3.1")
-    implementation("org.mongodb:mongodb-driver-sync:5.3.1")
+    implementation("org.mongodb:mongodb-driver-core:${mongoDriverVersion}")
+    implementation("org.mongodb:mongodb-driver-sync:${mongoDriverVersion}")

또는 Spring Data MongoDB를 사용하는 것을 고려해보세요:

+    implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
-    implementation("org.mongodb:mongodb-driver-core:5.3.1")
-    implementation("org.mongodb:mongodb-driver-sync:5.3.1")
📜 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 a06caf2.

📒 Files selected for processing (19)
  • build.gradle.kts (1 hunks)
  • src/main/java/com/example/demo/Application.java (1 hunks)
  • src/main/java/com/example/demo/application/CartService.java (1 hunks)
  • src/main/java/com/example/demo/controllers/CartController.java (1 hunks)
  • src/main/java/com/example/demo/controllers/LineItemController.java (1 hunks)
  • src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java (1 hunks)
  • src/main/java/com/example/demo/controllers/dtos/CartDto.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/CartRepository.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/LineItemRepository.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/ProductRepository.java (1 hunks)
  • 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/MongoTest.java (1 hunks)
  • src/test/java/com/example/demo/application/CartServiceTest.java (1 hunks)
  • src/test/java/com/example/demo/controllers/CartControllerTest.java (1 hunks)
  • src/test/java/com/example/demo/controllers/LineItemControllerTest.java (3 hunks)
  • src/test/java/com/example/demo/model/CartTest.java (1 hunks)
  • src/test/java/com/example/demo/model/LineItemTest.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/example/demo/model/Product.java
🔇 Additional comments (9)
src/main/java/com/example/demo/controllers/CartController.java (4)

3-7: 의존성 주입 및 DTO 임포트가 잘 이루어졌습니다.
Spring Boot 애플리케이션의 계층 구조에 맞춰 필요한 의존성과 DTO를 깔끔하게 불러오고 있습니다.


16-20: 생성자 주입 방식이 적절합니다.
스프링에서 권장하는 생성자 주입 방식을 잘 활용하여 CartService를 주입하고 있습니다.


23-31: 장바구니 상세 정보 반환 로직 검증
Cart 객체에서 LineItem 리스트를 DTO로 변환해 CartDto에 담아 반환하는 로직이 직관적이며 데이터 흐름이 명확합니다.
단, cart.getLineItems()가 null일 가능성이 전혀 없다면 괜찮으나, 혹시 모를 예외 상황을 고려해 방어적 코드를 추가하는 것도 좋습니다.


33-40: LineItem 매핑 로직이 깔끔합니다.
LineItem의 필드를 그대로 CartDto.LineItemDto로 매핑하여 DTO 구조를 명료하게 유지하고 있습니다.

src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java (1)

1-13: 필드 유효성 검증이 적절합니다.
@NotBlank@Positive 애너테이션을 사용해 productIdquantity의 유효 범위를 명확하게 설정하였으며, 입력 데이터 무결성을 보장하기에 적합합니다.

src/test/java/com/example/demo/controllers/CartControllerTest.java (1)

26-39: 테스트 구현이 잘 되었습니다!

CartService를 모킹하고 기본 장바구니 응답을 검증하는 테스트가 잘 구현되어 있습니다.

src/test/java/com/example/demo/controllers/LineItemControllerTest.java (1)

20-21: CartService 모의 객체가 적절히 추가되었습니다.

CartService를 @MockBean으로 주입하여 테스트 격리성을 잘 유지하고 있습니다.

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

16-20: 테스트 설정이 깔끔하게 구현되었습니다.

@beforeeach를 사용하여 테스트 데이터를 적절히 초기화하고 있습니다.


22-28: 빈 카트 테스트가 잘 구현되었습니다.

빈 카트의 총액이 0원인지 확인하는 기본 테스트가 잘 구현되어 있습니다.

Comment on lines +16 to +19
@Bean
public MongoClient mongoClient() {
return MongoClients.create("mongodb://localhost:27017");
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

MongoDB 연결 설정을 외부 구성으로 이동하세요.

하드코딩된 MongoDB 연결 문자열을 application.properties 또는 application.yml로 이동하여 환경별로 구성을 관리하는 것이 좋습니다.

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

+@Value("${spring.data.mongodb.uri}")
+private String mongoUri;

@Bean
public MongoClient mongoClient() {
-    return MongoClients.create("mongodb://localhost:27017");
+    return MongoClients.create(mongoUri);
}

그리고 application.yml에 다음을 추가하세요:

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017

Comment on lines +21 to +24
@Bean
public MongoDatabase mongoDatabase(MongoClient mongoClient) {
return mongoClient.getDatabase("demo");
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

데이터베이스 이름도 구성 파일로 이동하세요.

데이터베이스 이름도 외부 구성으로 관리하면 환경별로 다른 데이터베이스를 사용할 수 있습니다.

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

+@Value("${spring.data.mongodb.database}")
+private String databaseName;

@Bean
public MongoDatabase mongoDatabase(MongoClient mongoClient) {
-    return mongoClient.getDatabase("demo");
+    return mongoClient.getDatabase(databaseName);
}

그리고 application.yml에 다음을 추가하세요:

spring:
  data:
    mongodb:
      database: demo

Comment on lines +23 to +30
public void save(Cart cart) {
cart.getLineItems().forEach(lineItem -> {
if (lineItem.getId() == null) {
lineItemRepository.add(lineItem);
}
lineItemRepository.update(lineItem);
});
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

save 메서드의 로직을 개선하세요.

현재 구현에서는 모든 LineItem에 대해 불필요한 update가 수행될 수 있습니다. 또한 예외 처리가 누락되어 있습니다.

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

public void save(Cart cart) {
+    try {
        cart.getLineItems().forEach(lineItem -> {
            if (lineItem.getId() == null) {
                lineItemRepository.add(lineItem);
+            } else {
+                lineItemRepository.update(lineItem);
            }
-            lineItemRepository.update(lineItem);
        });
+    } catch (Exception e) {
+        throw new RuntimeException("장바구니 저장 중 오류가 발생했습니다.", e);
+    }
}
📝 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 save(Cart cart) {
cart.getLineItems().forEach(lineItem -> {
if (lineItem.getId() == null) {
lineItemRepository.add(lineItem);
}
lineItemRepository.update(lineItem);
});
}
public void save(Cart cart) {
try {
cart.getLineItems().forEach(lineItem -> {
if (lineItem.getId() == null) {
lineItemRepository.add(lineItem);
} else {
lineItemRepository.update(lineItem);
}
});
} catch (Exception e) {
throw new RuntimeException("장바구니 저장 중 오류가 발생했습니다.", e);
}
}

Comment on lines +17 to +29
@Test
void test() {

MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("demo");
MongoCollection<Document> collection = database.getCollection("products");

List<Document> documents = new ArrayList<>();
collection.find().into(documents);

assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

테스트 코드의 안정성을 개선하세요.

현재 테스트는 데이터베이스에 특정 데이터가 존재한다고 가정하고 있어 불안정할 수 있습니다. 또한 테스트 후 정리(cleanup)가 누락되어 있습니다.

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

+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MongoTest {
+    private MongoClient mongoClient;
+    private MongoDatabase database;
+    private MongoCollection<Document> collection;

+    @BeforeAll
+    void setUp() {
+        mongoClient = MongoClients.create("mongodb://localhost:27017");
+        database = mongoClient.getDatabase("demo");
+        collection = database.getCollection("products");
+    }

+    @BeforeEach
+    void prepare() {
+        // 테스트 데이터 설정
+        collection.insertMany(Arrays.asList(
+            new Document("name", "티셔츠"),
+            new Document("name", "청바지")
+        ));
+    }

+    @AfterEach
+    void cleanup() {
+        collection.deleteMany(new Document());
+    }

+    @AfterAll
+    void tearDown() {
+        mongoClient.close();
+    }

    @Test
    void test() {
-        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
-        MongoDatabase database = mongoClient.getDatabase("demo");
-        MongoCollection<Document> collection = database.getCollection("products");

        List<Document> documents = new ArrayList<>();
        collection.find().into(documents);

        assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
        assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
    }
}
📝 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
@Test
void test() {
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("demo");
MongoCollection<Document> collection = database.getCollection("products");
List<Document> documents = new ArrayList<>();
collection.find().into(documents);
assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MongoTest {
private MongoClient mongoClient;
private MongoDatabase database;
private MongoCollection<Document> collection;
@BeforeAll
void setUp() {
mongoClient = MongoClients.create("mongodb://localhost:27017");
database = mongoClient.getDatabase("demo");
collection = database.getCollection("products");
}
@BeforeEach
void prepare() {
// 테스트 데이터 설정
collection.insertMany(Arrays.asList(
new Document("name", "티셔츠"),
new Document("name", "청바지")
));
}
@AfterEach
void cleanup() {
collection.deleteMany(new Document());
}
@AfterAll
void tearDown() {
mongoClient.close();
}
@Test
void test() {
List<Document> documents = new ArrayList<>();
collection.find().into(documents);
assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
}

Comment on lines 23 to 32
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
void create() {
//
void create(
@Valid @RequestBody AddProductToCartDto addProductToCartDto
) {
cartService.addProduct(
addProductToCartDto.productId(),
addProductToCartDto.quantity()
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 응답 처리를 개선하세요.

현재 구현에서는 생성된 리소스에 대한 정보를 반환하지 않으며, 오류 처리도 누락되어 있습니다.

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

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
-void create(
+LineItemResponse create(
    @Valid @RequestBody AddProductToCartDto addProductToCartDto
) {
+    try {
-        cartService.addProduct(
+        LineItem lineItem = cartService.addProduct(
            addProductToCartDto.productId(),
            addProductToCartDto.quantity()
        );
+        return LineItemResponse.from(lineItem);
+    } catch (ProductNotFoundException e) {
+        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "상품을 찾을 수 없습니다.");
+    } catch (Exception e) {
+        throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "장바구니에 상품을 추가하는 중 오류가 발생했습니다.");
+    }
}
📝 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
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
void create() {
//
void create(
@Valid @RequestBody AddProductToCartDto addProductToCartDto
) {
cartService.addProduct(
addProductToCartDto.productId(),
addProductToCartDto.quantity()
);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
LineItemResponse create(
@Valid @RequestBody AddProductToCartDto addProductToCartDto
) {
try {
LineItem lineItem = cartService.addProduct(
addProductToCartDto.productId(),
addProductToCartDto.quantity()
);
return LineItemResponse.from(lineItem);
} catch (ProductNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "상품을 찾을 수 없습니다.");
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "장바구니에 상품을 추가하는 중 오류가 발생했습니다.");
}
}

Comment on lines +55 to +58
public void setProduct(Product product) {
this.productName = product.getName();
this.unitPrice = product.getPrice();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

상품 설정 시 검증 로직 필요

setProduct 메서드에서 null 상품에 대한 검증이 필요합니다.

 public void setProduct(Product product) {
+    if (product == null) {
+        throw new IllegalArgumentException("상품이 null일 수 없습니다.");
+    }
     this.productName = product.getName();
     this.unitPrice = product.getPrice();
 }
📝 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 setProduct(Product product) {
this.productName = product.getName();
this.unitPrice = product.getPrice();
}
public void setProduct(Product product) {
if (product == null) {
throw new IllegalArgumentException("상품이 null일 수 없습니다.");
}
this.productName = product.getName();
this.unitPrice = product.getPrice();
}

Comment on lines +51 to +53
public void addQuantity(int quantity) {
this.quantity += 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

수량 추가 시 검증 로직 필요

addQuantity 메서드에서 음수 수량이나 최대 허용 수량 초과에 대한 검증이 필요합니다.

 public void addQuantity(int quantity) {
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("추가할 수량은 0보다 커야 합니다.");
+    }
+    if (this.quantity + quantity > MAX_QUANTITY) {
+        throw new IllegalStateException("최대 허용 수량을 초과할 수 없습니다.");
+    }
     this.quantity += 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 addQuantity(int quantity) {
this.quantity += quantity;
}
public void addQuantity(int quantity) {
if (quantity <= 0) {
throw new IllegalArgumentException("추가할 수량은 0보다 커야 합니다.");
}
if (this.quantity + quantity > MAX_QUANTITY) {
throw new IllegalStateException("최대 허용 수량을 초과할 수 없습니다.");
}
this.quantity += quantity;
}

Comment on lines +12 to +21
public LineItem(String id, String productId, int quantity) {
this.id = id;
this.productId = productId;
this.quantity = quantity;
}

public LineItem(String productId, int quantity) {
this.productId = productId;
this.quantity = 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

생성자 입력값 검증 필요

생성자에서 입력값 검증이 누락되어 있습니다. 잘못된 입력으로 인한 문제를 방지하기 위해 다음과 같은 검증을 추가해 주세요:

 public LineItem(String id, String productId, int quantity) {
+    if (id == null || id.isEmpty()) {
+        throw new IllegalArgumentException("ID는 null이거나 비어있을 수 없습니다.");
+    }
+    if (productId == null || productId.isEmpty()) {
+        throw new IllegalArgumentException("상품 ID는 null이거나 비어있을 수 없습니다.");
+    }
+    if (quantity <= 0) {
+        throw new IllegalArgumentException("수량은 0보다 커야 합니다.");
+    }
     this.id = id;
     this.productId = productId;
     this.quantity = 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 LineItem(String id, String productId, int quantity) {
this.id = id;
this.productId = productId;
this.quantity = quantity;
}
public LineItem(String productId, int quantity) {
this.productId = productId;
this.quantity = quantity;
}
public LineItem(String id, String productId, int quantity) {
if (id == null || id.isEmpty()) {
throw new IllegalArgumentException("ID는 null이거나 비어있을 수 없습니다.");
}
if (productId == null || productId.isEmpty()) {
throw new IllegalArgumentException("상품 ID는 null이거나 비어있을 수 없습니다.");
}
if (quantity <= 0) {
throw new IllegalArgumentException("수량은 0보다 커야 합니다.");
}
this.id = id;
this.productId = productId;
this.quantity = quantity;
}
public LineItem(String productId, int quantity) {
this.productId = productId;
this.quantity = quantity;
}

Comment on lines +25 to +44
public Cart getCart() {

Cart cart = cartRepository.find();

List<String> productIds = cart.getLineItems().stream()
.map(LineItem::getProductId)
.toList();

Map<String, Product> products = new HashMap<>();
productRepository.findAllByIds(productIds).forEach(
product -> products.put(product.getId(), product)
);

cart.getLineItems().forEach(lineItem -> {
Product product = products.get(lineItem.getProductId());
lineItem.setProduct(product);
});

return cart;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

getCart 메서드에 안전성 개선이 필요합니다.

products Map에서 product를 조회할 때 null 체크가 없어 NullPointerException이 발생할 수 있습니다.

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

 cart.getLineItems().forEach(lineItem -> {
     Product product = products.get(lineItem.getProductId());
+    if (product == null) {
+        throw new ProductNotFoundException("Product not found with ID: " + lineItem.getProductId());
+    }
     lineItem.setProduct(product);
 });
📝 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 Cart getCart() {
Cart cart = cartRepository.find();
List<String> productIds = cart.getLineItems().stream()
.map(LineItem::getProductId)
.toList();
Map<String, Product> products = new HashMap<>();
productRepository.findAllByIds(productIds).forEach(
product -> products.put(product.getId(), product)
);
cart.getLineItems().forEach(lineItem -> {
Product product = products.get(lineItem.getProductId());
lineItem.setProduct(product);
});
return cart;
}
public Cart getCart() {
Cart cart = cartRepository.find();
List<String> productIds = cart.getLineItems().stream()
.map(LineItem::getProductId)
.toList();
Map<String, Product> products = new HashMap<>();
productRepository.findAllByIds(productIds).forEach(
product -> products.put(product.getId(), product)
);
cart.getLineItems().forEach(lineItem -> {
Product product = products.get(lineItem.getProductId());
if (product == null) {
throw new ProductNotFoundException("Product not found with ID: " + lineItem.getProductId());
}
lineItem.setProduct(product);
});
return cart;
}

Comment on lines +31 to +37
public void add(LineItem lineItem) {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity());

collection.insertOne(document);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

예외 처리가 필요합니다.

MongoDB 작업 시 발생할 수 있는 예외에 대한 처리가 없습니다.

다음과 같이 예외 처리를 추가하는 것을 제안합니다:

     public void add(LineItem lineItem) {
+        try {
             Document document = new Document()
                     .append("product_id", lineItem.getProductId())
                     .append("quantity", lineItem.getQuantity());
             collection.insertOne(document);
+        } catch (MongoException e) {
+            throw new RepositoryException("라인 아이템 추가 중 오류 발생", e);
+        }
     }
📝 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 add(LineItem lineItem) {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity());
collection.insertOne(document);
}
public void add(LineItem lineItem) {
try {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity());
collection.insertOne(document);
} catch (MongoException e) {
throw new RepositoryException("라인 아이템 추가 중 오류 발생", e);
}
}

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.

1 participant