Skip to content

test: 리뷰 관리 기능 테스트 코드 작성#277

Merged
conradrado merged 38 commits into
devfrom
test/267-review-test-code
Jul 6, 2026
Merged

test: 리뷰 관리 기능 테스트 코드 작성#277
conradrado merged 38 commits into
devfrom
test/267-review-test-code

Conversation

@conradrado

@conradrado conradrado commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

관련 이슈

작업 내용

  • 레포지토리 계층 테스트 코드 작성합니다.
  • 서비스 계층 테스트 코드 작성합니다.
  • 컨트롤러 계층 슬라이스 테스트 / 통합 테스트 작성합니다

변경 사항

  • 이전에 작업하던 feat: 리뷰 관리 기능 구현 브랜치를 rebase해서 작업하였습니다.
  • 서비스 / 레포지토리 계층 분리에 집중하였습니다.
  • enum으로 sortBy 구분 및 Review 예외를 몇개 추가하였습니다.

테스트 내용

  • 테스트 코드 작성
  • 로컬 테스트 완료
  • API 테스트 완료
  • 기타 테스트 완료

체크리스트

  • 코드 컨벤션을 지켰습니다.
  • 불필요한 코드를 제거했습니다.
  • 주석이 필요한 부분에 추가했습니다.
  • 관련 문서를 수정했습니다.
  • 리뷰어가 이해하기 쉽도록 작성했습니다.

리뷰 포인트

  • 중점적으로 봐줬으면 하는 부분을 작성해주세요.

스크린샷 / 참고 자료

  • 필요한 경우 첨부해주세요.

🔗 관련 이슈

  • close #267
  • close #268
  • close #269
  • close #282
  • close #283
  • close #284

📝 작업 내용

리뷰 관리 기능(조회/생성/수정/삭제)에 대해 변경이 생겼을 때 회귀를 빠르게 잡을 수 있도록, 컨트롤러–서비스–레포지토리 계층별 테스트를 추가하고 API/도메인 규칙을 “검증 가능한 형태”로 정리했습니다. 기존에는 리뷰 흐름이 구현 중심으로만 남아 인증/권한(401/403), 중복 생성(409), 커서 기반 페이지네이션(정렬/커서 타입/보조키의 일관성) 및 실패 케이스 예외–응답 매핑이 자동으로 검출되기 어려웠고, 이 때문에 코드래빗 자동 머지가 막히는 상황이 있었던 것으로 보입니다. 이를 해결하기 위해 이전 리뷰 구현 브랜치를 rebase한 뒤, 이번 PR에서 테스트와 변경 사항을 함께 맞물려 정돈했습니다.

주요 변경사항

  1. API 계약 고정 + 인증/권한 범위 강화

    • ReviewApi 인터페이스를 새로 두고 엔드포인트 시그니처/응답 문서를 고정한 뒤, ReviewController는 인증된 사용자 정보를 받아 ReviewService 호출로 역할을 좁혔습니다.
    • SecurityConfig에서 /api/reviews/** 접근을 .authenticated()로 제한해, 리뷰 API가 무단으로 호출되지 않도록 흐름을 명확히 했습니다.
  2. 정렬/커서 규칙을 enum/예외로 표준화(서비스 계층에서 검증 강화)

    • sortByReviewSortBy enum으로 분리하고, WebConfig에 문자열 파싱 컨버터를 추가해 컨트롤러 입력 단계부터 타입을 정규화했습니다.
    • 커서 기반 조회에서 cursor/idAfter 동시 제공 여부, 커서 타입-정렬 기준 불일치, 잘못된 커서 등 실패 조건을 전용 예외로 구분해 400으로 떨어지도록 했습니다.
    • 서비스 계층에서 cursor가 빈 문자열로 들어올 때 null로 처리하도록 수정해(제공된 커밋 요약 기준) 빈 값이 그대로 파싱되어 조회 로직을 어긋나게 만들던 문제를 완화했습니다.
    • 중복 리뷰 생성은 ReviewAlreadyExistsException(409), 존재하지 않는 리뷰는 ReviewNotFoundException(404), 작성자 검증 실패는 ReviewForbiddenException(403)으로 일관되게 매핑되도록 예외 체계를 확장했습니다.
  3. 데이터 흐름/조회 책임 분리 + 계층별 테스트로 회귀 방지

    • 리뷰 조회는 ReviewQueryRepository/ReviewQueryRepositoryImpl에서 커서+보조키 방식으로 정렬 경계를 구성하고(타이브레이커 포함), ReviewService는 페이지네이션 계산(예: hasNext, nextCursor, nextIdAfter)과 커서/정렬 파싱 검증에 집중하도록 흐름을 나눴습니다.
    • 테스트 전략도 계층별로 분리했습니다.
      • 컨트롤러: @WebMvcTest로 인증/권한/검증/예외 응답 및 서비스 호출 여부를 슬라이스 수준에서 검증
      • 서비스: Mockito 단위 테스트로 커서 기반 다음 페이지 계산 및 분기(생성/수정/삭제, 예외 케이스)를 검증
      • 레포지토리: @DataJpaTest로 유니크 제약, 존재 여부/카운트, 커서 페이지네이션이 이어지고 정렬 규칙이 지켜지는지를 검증
      • 컨트롤러 통합: MockMvc 기반으로 인증/CSRF를 포함한 요청 흐름과 DB 반영까지 확인

📊 변경 효과 요약 (가능한 경우에만)

  • 신규 테스트 파일: 4개
    • ReviewControllerTest (492 lines)
    • ReviewControllerIntegrationTest (349 lines)
    • ReviewServiceTest (340 lines)
    • ReviewRepositoryTest (319 lines)
  • 테스트 코드 라인 증가: 총 1,500줄(제공된 요약의 Lines changed 합산 기준)
  • 소스 코드 라인/총 파일 수 및 전체 라인 증감: 측정하지 않음

conradrado added 18 commits July 3, 2026 11:01
- 리뷰 업데이트 요청 DTO 작성
- 리뷰 생성 요청 DTO 작성
- ReviewApi와 Controller 단에서는 유저 인증 객체를 MoplPrincipal로 받아오는것으로 구현
- ReviewResponseDto가  User 정보(리뷰 작성자)를 가지고 있어서 Dto로 매핑 시 User의 정보가 필요
- Service 계층에서 create 시 request에 담긴 content id를 기반으로 해당 컨텐츠가 존재하는 지 검증
- Repository 에서는 cursor와 idAfter가 둘다 널이거나 둘 다 존재하도록 검증
- Review 엔티티에서 rating 검증 프라이빗 메서드 작성
- Entity에서 ContentId 직접 참조 대신 @manytoone 적용으로 JPA 수준 참조 무결성 확보
@conradrado conradrado self-assigned this Jul 5, 2026
@conradrado conradrado added the test test 코드 작성 관련 label Jul 5, 2026
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

리뷰 도메인 전반이 추가되었습니다. 요청/응답 DTO, 리뷰 엔티티, 정렬·커서 예외, 매퍼, 저장소, 서비스, 컨트롤러가 생겼고 /api/reviews는 인증이 필요하도록 제한되었습니다. 조회는 커서 기반 페이지네이션으로 처리되며, 생성/수정/삭제는 작성자 검증과 중복 작성 검사를 포함합니다. 컨트롤러 슬라이스, 통합, 서비스, 저장소 테스트도 함께 추가되었습니다.

Estimated code review effort: 4 (Complex) | ~60분

Possibly related PRs

  • sb10-part4-team5/sb10-mopl-team5#96: SecurityConfig의 인가 규칙을 수정해 특정 경로 접근 정책을 바꾸는 점이 이번 변경의 /api/reviews/** 제한과 직접 맞닿아 있습니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning #267,#268,#269,#282,#283은 충족했지만, Review 엔티티가 여전히 User 연관관계를 직접 참조해 #284의 핵심 목표는 미달입니다. Review에 authorId/contentId를 직접 저장하도록 바꾸고, User 조회와 응답 매핑은 서비스/매퍼로 분리해 #284 요구를 맞추세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed 테스트 추가와 함께 포함된 구현·리팩토링 변경은 연결된 이슈 범위 안에 있어 보이며, 별도의 무관한 변경은 보이지 않습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed 리뷰 관리 기능의 테스트 코드 작성이라는 핵심 변경을 간결하게 잘 드러냅니다.
Description check ✅ Passed 템플릿의 주요 섹션을 대부분 채웠고 이슈, 작업 내용, 변경 사항, 테스트, 체크리스트가 포함되어 있습니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/267-review-test-code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java`:
- Around line 66-105: deleteReview의 인증 주체 타입을 MoplPrincipal로 통일해야 합니다. 현재
ReviewApi의 deleteReview만 MoplUserDetails를 받고 있는데, 이미 MoplUserDetails가
MoplPrincipal을 구현하고 있고 메서드에서는 getId()만 사용하므로, deleteReview 시그니처와 관련 사용처를
MoplPrincipal 기준으로 맞춰 API 계약을 일관되게 정리하세요. ReviewApi의 createReview/updateReview와
동일한 인증 주체 타입을 유지하도록 수정하면 됩니다.

In
`@src/main/java/com/codeit/team5/mopl/review/dto/request/ReviewUpdateRequest.java`:
- Around line 10-20: `ReviewUpdateRequest`가 `@NotBlank`와 `@NotNull` 때문에 PATCH에서
부분 수정이 막혀 있습니다. `text`와 `rating`을 선택 입력으로 바꾸고, `ReviewService.updateReview`에서
`review.update(...)`처럼 둘 다 덮어쓰지 말고 null이 아닌 값만 반영하도록 `Review` 업데이트 로직을 함께 수정하세요.
만약 항상 둘 다 받는 설계라면 PATCH 대신 PUT으로 맞추고, 관련 검증과 서비스 동작을 같은 기준으로 정리하세요.

In
`@src/main/java/com/codeit/team5/mopl/review/exception/InvalidRatingException.java`:
- Around line 6-12: InvalidRatingException is a duplicate unused exception that
is not referenced by ReviewCreateRequest, ReviewUpdateRequest, or ReviewService.
Remove the InvalidRatingException class if no service-layer validation is
needed, or otherwise wire it into the actual review create/update flow where
rating validation is performed so the exception is meaningfully used.

In
`@src/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepositoryImpl.java`:
- Around line 57-79: 커서 파싱 실패 시 원본 예외의 스택 트레이스를 유지하도록 수정하세요.
ReviewQueryRepositoryImpl의 커서 파싱 로직에서 NumberFormatException과
DateTimeParseException을 잡아 InvalidCursorException을 던질 때, 기존의 new
InvalidCursorException() 대신 예외 e를 cause로 전달하는 생성자를 사용해 원인 정보를 보존하세요.
InvalidCursorException에 message/cause 생성자가 있으면 이를 사용하고, 없으면 해당 예외 타입에 cause 전달
경로를 추가한 뒤 이 두 catch 블록 모두에 적용하세요.

In `@src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java`:
- Around line 105-110: In ReviewService.review creation flow, the
DataIntegrityViolationException catch block drops the original stack trace when
converting to ReviewAlreadyExistsException. Update the catch in ReviewService
around reviewRepository.saveAndFlush to pass the caught exception as the cause
when throwing ReviewAlreadyExistsException, matching the same preservation
pattern used in the repository layer. Keep the existing warning log, but ensure
the original DB constraint violation is retained for debugging.

In `@src/test/java/com/codeit/team5/mopl/review/service/ReviewServiceTest.java`:
- Around line 59-179: getReviews 테스트에 ASCENDING 분기 커버리지가 빠져 있습니다;
ReviewServiceTest의 getReviews 호출 케이스들처럼 ReviewService.getReviews와
resolveAscending(sortBy, sortDirection) 경로를 직접 검증하는 테스트를 하나 추가해 ASCENDING일 때
repository 조회가 ascending=true로 호출되는지 확인하세요. 기존 createdAt 또는 rating 케이스를 재사용해 정렬
방향만 "ASCENDING"으로 바꾸고, reviewRepository.findPageByContentId 호출 인자와
nextCursor/결과가 기대대로 나오는지 함께 검증하면 됩니다.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e860f02e-f525-40d9-b66f-6e4cb5b6f1a0

📥 Commits

Reviewing files that changed from the base of the PR and between 384c942 and 2e7682a.

📒 Files selected for processing (20)
  • src/main/java/com/codeit/team5/mopl/config/SecurityConfig.java
  • src/main/java/com/codeit/team5/mopl/review/controller/ReviewController.java
  • src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java
  • src/main/java/com/codeit/team5/mopl/review/dto/request/ReviewCreateRequest.java
  • src/main/java/com/codeit/team5/mopl/review/dto/request/ReviewUpdateRequest.java
  • src/main/java/com/codeit/team5/mopl/review/dto/response/ReviewResponse.java
  • src/main/java/com/codeit/team5/mopl/review/entity/Review.java
  • src/main/java/com/codeit/team5/mopl/review/exception/InvalidRatingException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/InvalidReviewSortByException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/ReviewAlreadyExistsException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/ReviewForbiddenException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/ReviewNotFoundException.java
  • src/main/java/com/codeit/team5/mopl/review/mapper/ReviewMapper.java
  • src/main/java/com/codeit/team5/mopl/review/repository/ReviewRepository.java
  • src/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepository.java
  • src/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepositoryImpl.java
  • src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java
  • src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java
  • src/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.java
  • src/test/java/com/codeit/team5/mopl/review/service/ReviewServiceTest.java

Comment thread src/main/java/com/codeit/team5/mopl/review/exception/InvalidRatingException.java Outdated
Comment thread src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java Outdated
@conradrado conradrado requested a review from dstle July 5, 2026 10:13
plzslp
plzslp previously approved these changes Jul 5, 2026
Comment thread src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java Outdated

@metDaisy metDaisy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

리뷰 기능 먼저 다 하고 테스트 작성은 이후에 하는 건 어떤가요 ?

@conradrado

Copy link
Copy Markdown
Collaborator Author

리뷰 기능 먼저 다 하고 테스트 작성은 이후에 하는 건 어떤가요 ?

어제 기능 구현 PR에 달아주신 리뷰를 이제 봐서 수정중입니다! 리뷰 기능 PR은 테스트 코드 작성이 안되어있어서 그런지 코드래빗이 머지를 막는 것 같아 해당 PR에 git rebase 한 후 머지 중입니답

- Cursor,SortBy와 같은 커서 페이지네이션에 필요한 파라미터들은 서비스계층에서 최대한 검증하는 방향으로 진행하였습니다.
- Controller, Service는 리뷰 커서 페이지네이션 조회를 할 때 파라미터 뭉치를 받지 않고 Dto를 받고 호출합니다.
- 레포지토리는 데이터를 넣고 조회하는 것에만 집중하도록 코드를 개편하였습니다.
- null값이 들어오면 서비스 계층에서 default 값으로 대체합니다.
- 이제 Review는 User를 직접 참조하므로 author.getId() -> author 형식으로 변경
- ReviewSortBy, Sort.Direction을 서비스 계층에 적용

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/main/java/com/codeit/team5/mopl/review/entity/Review.java (1)

19-20: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

동시 중복 리뷰 요청은 409로 흡수해야 합니다.
existsByContent_IdAndAuthor_Idsave()라서 같은 사용자/콘텐츠에 대한 거의 동시 요청은 둘 다 검사를 통과할 수 있고, 한쪽은 DB uniqueConstraints에서 DataIntegrityViolationException으로 떨어집니다. 지금 ReviewAlreadyExistsException은 409로 매핑되지만, 이 경로는 그 예외를 거치지 않아서 전역 예외 처리에 걸리면 500이 됩니다.
ReviewService.createReview에서 save()try-catch로 감싸 ReviewAlreadyExistsException으로 변환하거나, 최소한 DataIntegrityViolationException을 409로 매핑하는 핸들러를 추가해 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/codeit/team5/mopl/review/entity/Review.java` around lines
19 - 20, In ReviewService.createReview, the existsByContent_IdAndAuthor_Id then
save path can still race under concurrent requests and bypass
ReviewAlreadyExistsException, causing a DataIntegrityViolationException from the
reviews unique constraint. Wrap the save() call in a try-catch and convert that
persistence exception into ReviewAlreadyExistsException, or add an exception
handler that maps DataIntegrityViolationException to 409. Use
ReviewService.createReview and ReviewAlreadyExistsException as the main symbols
to locate and update the flow.
src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java (1)

26-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

GET 쿼리 DTO는 @ParameterObject로 펼쳐서 문서화하세요

springdoc-openapi 2.8.17에서는 org.springdoc.core.annotations.ParameterObject를 붙여야 ReviewGetRequest의 필드가 개별 쿼리 파라미터로 노출됩니다. 지금처럼 @Valid ReviewGetRequest request만 두면 Swagger UI에서 contentId, cursor, limit 같은 제약/설명이 잘 보이지 않을 수 있습니다.

  • 이 메서드에만 붙이면 됨: 변경 범위가 작고, 기존 @Min/@Max 의미를 문서에 살리기 좋음
  • 전역 설정(springdoc.default-flat-param-object=true)도 가능하지만, 영향 범위가 넓어서 이 케이스엔 메서드 단위 적용이 더 안전함

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java`
around lines 26 - 37, getReviews 메서드의 GET 쿼리 DTO가 Swagger에서 개별 파라미터로 펼쳐지지 않는 문제를
수정하세요. ReviewApi의 getReviews 파라미터인 ReviewGetRequest에
org.springdoc.core.annotations.ParameterObject를 추가해 contentId, cursor, limit 같은
필드가 각 쿼리 파라미터로 문서화되도록 하세요. `@Valid는` 유지하고, 이 메서드 단위로만 적용해서 ReviewGetRequest의 제약과
설명이 Swagger UI에 잘 노출되게 맞추면 됩니다.
src/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.java (1)

147-270: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

정렬 키가 동일한 경우(동률)의 커서 페이지네이션 테스트가 없습니다.

createdAt/rating 값이 동일한 리뷰가 여러 개 있을 때도 커서 페이지네이션이 안정적으로(중복/누락 없이) 동작하는지 검증하는 테스트가 빠져 있습니다. 커서 기반 페이지네이션은 정렬 키에 동률이 있을 때 보조 정렬 기준(예: id)이 없으면 항목이 중복되거나 누락되는 문제가 흔하게 발생합니다. setCreatedAt 헬퍼가 이미 있으니, 두 리뷰에 동일한 createdAt(또는 rating)을 부여하고 페이지가 겹치지 않는지 검증하는 테스트를 추가하면 회귀 방지에 도움이 될 것 같습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.java`
around lines 147 - 270, The pagination tests in ReviewRepositoryTest cover only
distinct sort-key values and miss tie cases for createdAt/rating. Add a new
cursor-pagination test using the existing findPageByContentIdSortByCreatedAt
and/or findPageByContentIdSortByRating methods where at least two reviews share
the same createdAt (use setCreatedAt) or rating, then page through results and
assert there are no duplicates or gaps between pages. Make sure the test
verifies stable behavior when the sort key ties occur, ideally by checking the
returned ids do not overlap across pages.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/codeit/team5/mopl/review/contant/ReviewSortBy.java`:
- Around line 29-35: `ReviewSortBy.parse`는 현재 `catch (Exception e)`에서 원인 예외를 버리고
`ReviewSortByMismatchException`만 새로 던져 스택 트레이스를 잃고 있습니다. `parser.apply(cursor)`
실패 시 잡은 `e`를 원인으로 보존해 재발생하도록 `ReviewSortByMismatchException`에 `Throwable cause`를
받는 생성자를 추가하거나 기존 생성자를 확장하고, `parse`에서 그 생성자를 사용해 파싱 실패의 실제
원인(`NumberFormatException`, `DateTimeParseException` 등)이 유지되게 수정하세요.
- Around line 13-27: `ReviewSortBy.from` and the `sortByType` mapping are
inconsistent with request binding, since the API currently accepts enum names
but the enum stores lowercase values for responses. Update `ReviewSortBy` so the
request/response contract uses one consistent `sortBy` format, and make sure any
parser/binding logic that relies on `CREATED_AT` and `RATING` versus `createdAt`
and `rating` is aligned with the chosen contract. Keep the fix localized to
`ReviewSortBy` and any related converter/binding code so the same values are
accepted and returned everywhere.

In `@src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java`:
- Around line 102-117: The createReview flow in ReviewService should rely on the
database unique constraint and convert any duplicate insert failure into
ReviewAlreadyExistsException instead of leaking a 500. Keep the existing lookup
logic, but wrap the reviewRepository save/saveAndFlush call in a try/catch for
DataIntegrityViolationException so concurrent duplicate requests are translated
to the same 409 path as the existing duplicate check. Use the createReview
method and ReviewAlreadyExistsException as the key points to update.

---

Outside diff comments:
In `@src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java`:
- Around line 26-37: getReviews 메서드의 GET 쿼리 DTO가 Swagger에서 개별 파라미터로 펼쳐지지 않는 문제를
수정하세요. ReviewApi의 getReviews 파라미터인 ReviewGetRequest에
org.springdoc.core.annotations.ParameterObject를 추가해 contentId, cursor, limit 같은
필드가 각 쿼리 파라미터로 문서화되도록 하세요. `@Valid는` 유지하고, 이 메서드 단위로만 적용해서 ReviewGetRequest의 제약과
설명이 Swagger UI에 잘 노출되게 맞추면 됩니다.

In `@src/main/java/com/codeit/team5/mopl/review/entity/Review.java`:
- Around line 19-20: In ReviewService.createReview, the
existsByContent_IdAndAuthor_Id then save path can still race under concurrent
requests and bypass ReviewAlreadyExistsException, causing a
DataIntegrityViolationException from the reviews unique constraint. Wrap the
save() call in a try-catch and convert that persistence exception into
ReviewAlreadyExistsException, or add an exception handler that maps
DataIntegrityViolationException to 409. Use ReviewService.createReview and
ReviewAlreadyExistsException as the main symbols to locate and update the flow.

In
`@src/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.java`:
- Around line 147-270: The pagination tests in ReviewRepositoryTest cover only
distinct sort-key values and miss tie cases for createdAt/rating. Add a new
cursor-pagination test using the existing findPageByContentIdSortByCreatedAt
and/or findPageByContentIdSortByRating methods where at least two reviews share
the same createdAt (use setCreatedAt) or rating, then page through results and
assert there are no duplicates or gaps between pages. Make sure the test
verifies stable behavior when the sort key ties occur, ideally by checking the
returned ids do not overlap across pages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 18e81613-b8e5-4977-804f-ff83ac24b8ff

📥 Commits

Reviewing files that changed from the base of the PR and between 94c6a53 and 4ccae25.

📒 Files selected for processing (17)
  • src/main/java/com/codeit/team5/mopl/review/contant/ReviewSortBy.java
  • src/main/java/com/codeit/team5/mopl/review/controller/ReviewController.java
  • src/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.java
  • src/main/java/com/codeit/team5/mopl/review/dto/request/ReviewGetRequest.java
  • src/main/java/com/codeit/team5/mopl/review/entity/Review.java
  • src/main/java/com/codeit/team5/mopl/review/exception/CursorIdAfterNotTogetherException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/InvalidCursorException.java
  • src/main/java/com/codeit/team5/mopl/review/exception/ReviewSortByMismatchException.java
  • src/main/java/com/codeit/team5/mopl/review/mapper/ReviewMapper.java
  • src/main/java/com/codeit/team5/mopl/review/repository/ReviewRepository.java
  • src/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepository.java
  • src/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepositoryImpl.java
  • src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java
  • src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java
  • src/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.java
  • src/test/java/com/codeit/team5/mopl/review/service/ReviewServiceTest.java

- 이제 응답의 sortBy: createdAt을 클ㄹ라이언트가 그대로 다음 요청에 재사용해도 400이 나지 않고 정상적인 바인딩이 됩니다

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java (1)

207-332: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

테스트 메서드 네이밍 일관성 개선을 제안합니다.

이 클래스의 POST 테스트들은 ofReview_* 접두사를 사용하지만, ReviewControllerIntegrationTest의 동일 엔드포인트 테스트들은 createReview_* 접두사를 사용합니다. ofReview라는 이름은 Review.of() 팩토리 메서드와 혼동을 줄 수 있어, 두 테스트 클래스 간 네이밍을 통일하면 가독성과 검색성이 개선될 것 같습니다.

♻️ 제안하는 리팩터링 방향
-    void ofReview_success() throws Exception {
+    void createReview_success() throws Exception {
...
-    void ofReview_unauthenticated_returns401() throws Exception {
+    void createReview_unauthenticated_returns401() throws Exception {
...
-    void ofReview_missingContentId_returns400() throws Exception {
+    void createReview_missingContentId_returns400() throws Exception {
...
-    void ofReview_ratingOver5_returns400() throws Exception {
+    void createReview_ratingOver5_returns400() throws Exception {
...
-    void ofReview_ratingUnder0_returns400() throws Exception {
+    void createReview_ratingUnder0_returns400() throws Exception {
...
-    void ofReview_alreadyExists_returns409() throws Exception {
+    void createReview_alreadyExists_returns409() throws Exception {
...
-    void ofReview_contentNotFound_returns404() throws Exception {
+    void createReview_contentNotFound_returns404() throws Exception {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java`
around lines 207 - 332, The POST test method names in ReviewControllerTest are
inconsistent with ReviewControllerIntegrationTest and the current prefix can be
confused with Review.of(); rename the existing ofReview_* tests to use the same
createReview_* pattern as the integration tests. Update the affected test
methods in ReviewControllerTest so the naming is uniform, searchable, and
clearly tied to the ReviewController#createReview flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java`:
- Around line 207-332: The POST test method names in ReviewControllerTest are
inconsistent with ReviewControllerIntegrationTest and the current prefix can be
confused with Review.of(); rename the existing ofReview_* tests to use the same
createReview_* pattern as the integration tests. Update the affected test
methods in ReviewControllerTest so the naming is uniform, searchable, and
clearly tied to the ReviewController#createReview flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe5bb634-8a5b-499a-ae2c-5a2b73853a36

📥 Commits

Reviewing files that changed from the base of the PR and between 4ccae25 and 6b6c367.

📒 Files selected for processing (3)
  • src/main/java/com/codeit/team5/mopl/config/WebConfig.java
  • src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java

@conradrado conradrado requested review from metDaisy and plzslp July 5, 2026 17:20
- 이전에는 cursor가 blank 빈 문자열로 들어오면 해당 값을 빈 문자열로 인식하여 조회가 안되던 문제 해결

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java (1)

158-163: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

rating 커서에 비유한값을 막아주세요. Double.parseDouble()NaN/Infinity를 통과시키는데, 이 값들이 그대로 r.rating.lt/gt/eq 비교로 흘러가면 페이지 경계가 의미 없어지고 DB별 결과도 달라질 수 있습니다. parseDouble() 뒤에 Double.isFinite(parsed)로 한 번 더 거르는 방식이 가장 간단합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java` around
lines 158 - 163, The rating cursor parser in ReviewService.parseDoubleCursor
currently accepts non-finite values like NaN and Infinity, which should be
rejected before they reach r.rating.lt/gt/eq comparisons. Update
parseDoubleCursor to parse the string, then validate the result with
Double.isFinite(parsed) and throw InvalidCursorException when the value is not
finite. Keep the change localized to parseDoubleCursor so all rating cursor
handling uses the same validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java`:
- Around line 158-163: The rating cursor parser in
ReviewService.parseDoubleCursor currently accepts non-finite values like NaN and
Infinity, which should be rejected before they reach r.rating.lt/gt/eq
comparisons. Update parseDoubleCursor to parse the string, then validate the
result with Double.isFinite(parsed) and throw InvalidCursorException when the
value is not finite. Keep the change localized to parseDoubleCursor so all
rating cursor handling uses the same validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8be82ac3-bfa5-45f4-bd89-9960caf55d07

📥 Commits

Reviewing files that changed from the base of the PR and between 6b6c367 and 6beea71.

📒 Files selected for processing (1)
  • src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java

Comment thread src/main/java/com/codeit/team5/mopl/review/mapper/ReviewMapper.java Outdated
metDaisy
metDaisy previously approved these changes Jul 6, 2026
plzslp
plzslp previously approved these changes Jul 6, 2026
- service 계층에서 cursor 값 파싱 시 ReviewSortBy의 parse 활용
- ReviewMapper는 review만 다루고 UserSummaryResponse는 uses 옵션을 활용하여 userMapper 사용
@conradrado conradrado dismissed stale reviews from plzslp and metDaisy via 3ba47d8 July 6, 2026 00:55
@conradrado conradrado merged commit a7e9ab1 into dev Jul 6, 2026
2 checks passed
@conradrado conradrado deleted the test/267-review-test-code branch July 6, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test test 코드 작성 관련

Projects

None yet

3 participants