test: 리뷰 관리 기능 테스트 코드 작성#277
Conversation
- 리뷰 업데이트 요청 DTO 작성 - 리뷰 생성 요청 DTO 작성 - ReviewApi와 Controller 단에서는 유저 인증 객체를 MoplPrincipal로 받아오는것으로 구현
- ReviewResponseDto가 User 정보(리뷰 작성자)를 가지고 있어서 Dto로 매핑 시 User의 정보가 필요
…eam5 into feat/220-contents-review
…eam5 into feat/220-contents-review
- Service 계층에서 create 시 request에 담긴 content id를 기반으로 해당 컨텐츠가 존재하는 지 검증 - Repository 에서는 cursor와 idAfter가 둘다 널이거나 둘 다 존재하도록 검증 - Review 엔티티에서 rating 검증 프라이빗 메서드 작성
…nessException으로 교체
- Entity에서 ContentId 직접 참조 대신 @manytoone 적용으로 JPA 수준 참조 무결성 확보
…eam5 into test/267-review-test-code
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough리뷰 도메인 전반이 추가되었습니다. 요청/응답 DTO, 리뷰 엔티티, 정렬·커서 예외, 매퍼, 저장소, 서비스, 컨트롤러가 생겼고 Estimated code review effort: 4 (Complex) | ~60분 Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (20)
src/main/java/com/codeit/team5/mopl/config/SecurityConfig.javasrc/main/java/com/codeit/team5/mopl/review/controller/ReviewController.javasrc/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.javasrc/main/java/com/codeit/team5/mopl/review/dto/request/ReviewCreateRequest.javasrc/main/java/com/codeit/team5/mopl/review/dto/request/ReviewUpdateRequest.javasrc/main/java/com/codeit/team5/mopl/review/dto/response/ReviewResponse.javasrc/main/java/com/codeit/team5/mopl/review/entity/Review.javasrc/main/java/com/codeit/team5/mopl/review/exception/InvalidRatingException.javasrc/main/java/com/codeit/team5/mopl/review/exception/InvalidReviewSortByException.javasrc/main/java/com/codeit/team5/mopl/review/exception/ReviewAlreadyExistsException.javasrc/main/java/com/codeit/team5/mopl/review/exception/ReviewForbiddenException.javasrc/main/java/com/codeit/team5/mopl/review/exception/ReviewNotFoundException.javasrc/main/java/com/codeit/team5/mopl/review/mapper/ReviewMapper.javasrc/main/java/com/codeit/team5/mopl/review/repository/ReviewRepository.javasrc/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepository.javasrc/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepositoryImpl.javasrc/main/java/com/codeit/team5/mopl/review/service/ReviewService.javasrc/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.javasrc/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.javasrc/test/java/com/codeit/team5/mopl/review/service/ReviewServiceTest.java
metDaisy
left a comment
There was a problem hiding this comment.
리뷰 기능 먼저 다 하고 테스트 작성은 이후에 하는 건 어떤가요 ?
어제 기능 구현 PR에 달아주신 리뷰를 이제 봐서 수정중입니다! 리뷰 기능 PR은 테스트 코드 작성이 안되어있어서 그런지 코드래빗이 머지를 막는 것 같아 해당 PR에 git rebase 한 후 머지 중입니답 |
- Cursor,SortBy와 같은 커서 페이지네이션에 필요한 파라미터들은 서비스계층에서 최대한 검증하는 방향으로 진행하였습니다. - Controller, Service는 리뷰 커서 페이지네이션 조회를 할 때 파라미터 뭉치를 받지 않고 Dto를 받고 호출합니다. - 레포지토리는 데이터를 넣고 조회하는 것에만 집중하도록 코드를 개편하였습니다.
- null값이 들어오면 서비스 계층에서 default 값으로 대체합니다.
- 이제 Review는 User를 직접 참조하므로 author.getId() -> author 형식으로 변경 - ReviewSortBy, Sort.Direction을 서비스 계층에 적용
…eam5 into test/267-review-test-code
There was a problem hiding this comment.
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_Id후save()라서 같은 사용자/콘텐츠에 대한 거의 동시 요청은 둘 다 검사를 통과할 수 있고, 한쪽은 DBuniqueConstraints에서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 winGET 쿼리 DTO는
@ParameterObject로 펼쳐서 문서화하세요
springdoc-openapi2.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
📒 Files selected for processing (17)
src/main/java/com/codeit/team5/mopl/review/contant/ReviewSortBy.javasrc/main/java/com/codeit/team5/mopl/review/controller/ReviewController.javasrc/main/java/com/codeit/team5/mopl/review/controller/api/ReviewApi.javasrc/main/java/com/codeit/team5/mopl/review/dto/request/ReviewGetRequest.javasrc/main/java/com/codeit/team5/mopl/review/entity/Review.javasrc/main/java/com/codeit/team5/mopl/review/exception/CursorIdAfterNotTogetherException.javasrc/main/java/com/codeit/team5/mopl/review/exception/InvalidCursorException.javasrc/main/java/com/codeit/team5/mopl/review/exception/ReviewSortByMismatchException.javasrc/main/java/com/codeit/team5/mopl/review/mapper/ReviewMapper.javasrc/main/java/com/codeit/team5/mopl/review/repository/ReviewRepository.javasrc/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepository.javasrc/main/java/com/codeit/team5/mopl/review/repository/querydsl/ReviewQueryRepositoryImpl.javasrc/main/java/com/codeit/team5/mopl/review/service/ReviewService.javasrc/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerIntegrationTest.javasrc/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.javasrc/test/java/com/codeit/team5/mopl/review/repository/ReviewRepositoryTest.javasrc/test/java/com/codeit/team5/mopl/review/service/ReviewServiceTest.java
- 이제 응답의 sortBy: createdAt을 클ㄹ라이언트가 그대로 다음 요청에 재사용해도 400이 나지 않고 정상적인 바인딩이 됩니다
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
src/main/java/com/codeit/team5/mopl/config/WebConfig.javasrc/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerIntegrationTest.javasrc/test/java/com/codeit/team5/mopl/review/controller/ReviewControllerTest.java
- 이전에는 cursor가 blank 빈 문자열로 들어오면 해당 값을 빈 문자열로 인식하여 조회가 안되던 문제 해결
There was a problem hiding this comment.
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 winrating 커서에 비유한값을 막아주세요.
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
📒 Files selected for processing (1)
src/main/java/com/codeit/team5/mopl/review/service/ReviewService.java
- service 계층에서 cursor 값 파싱 시 ReviewSortBy의 parse 활용 - ReviewMapper는 review만 다루고 UserSummaryResponse는 uses 옵션을 활용하여 userMapper 사용
…eam5 into test/267-review-test-code
관련 이슈
작업 내용
변경 사항
테스트 내용
체크리스트
리뷰 포인트
스크린샷 / 참고 자료
🔗 관련 이슈
#267#268#269#282#283#284📝 작업 내용
리뷰 관리 기능(조회/생성/수정/삭제)에 대해 변경이 생겼을 때 회귀를 빠르게 잡을 수 있도록, 컨트롤러–서비스–레포지토리 계층별 테스트를 추가하고 API/도메인 규칙을 “검증 가능한 형태”로 정리했습니다. 기존에는 리뷰 흐름이 구현 중심으로만 남아 인증/권한(401/403), 중복 생성(409), 커서 기반 페이지네이션(정렬/커서 타입/보조키의 일관성) 및 실패 케이스 예외–응답 매핑이 자동으로 검출되기 어려웠고, 이 때문에 코드래빗 자동 머지가 막히는 상황이 있었던 것으로 보입니다. 이를 해결하기 위해 이전 리뷰 구현 브랜치를 rebase한 뒤, 이번 PR에서 테스트와 변경 사항을 함께 맞물려 정돈했습니다.
주요 변경사항
API 계약 고정 + 인증/권한 범위 강화
ReviewApi인터페이스를 새로 두고 엔드포인트 시그니처/응답 문서를 고정한 뒤,ReviewController는 인증된 사용자 정보를 받아ReviewService호출로 역할을 좁혔습니다.SecurityConfig에서/api/reviews/**접근을.authenticated()로 제한해, 리뷰 API가 무단으로 호출되지 않도록 흐름을 명확히 했습니다.정렬/커서 규칙을 enum/예외로 표준화(서비스 계층에서 검증 강화)
sortBy를ReviewSortByenum으로 분리하고,WebConfig에 문자열 파싱 컨버터를 추가해 컨트롤러 입력 단계부터 타입을 정규화했습니다.cursor/idAfter동시 제공 여부, 커서 타입-정렬 기준 불일치, 잘못된 커서 등 실패 조건을 전용 예외로 구분해 400으로 떨어지도록 했습니다.cursor가 빈 문자열로 들어올 때null로 처리하도록 수정해(제공된 커밋 요약 기준) 빈 값이 그대로 파싱되어 조회 로직을 어긋나게 만들던 문제를 완화했습니다.ReviewAlreadyExistsException(409), 존재하지 않는 리뷰는ReviewNotFoundException(404), 작성자 검증 실패는ReviewForbiddenException(403)으로 일관되게 매핑되도록 예외 체계를 확장했습니다.데이터 흐름/조회 책임 분리 + 계층별 테스트로 회귀 방지
ReviewQueryRepository/ReviewQueryRepositoryImpl에서 커서+보조키 방식으로 정렬 경계를 구성하고(타이브레이커 포함),ReviewService는 페이지네이션 계산(예:hasNext,nextCursor,nextIdAfter)과 커서/정렬 파싱 검증에 집중하도록 흐름을 나눴습니다.@WebMvcTest로 인증/권한/검증/예외 응답 및 서비스 호출 여부를 슬라이스 수준에서 검증@DataJpaTest로 유니크 제약, 존재 여부/카운트, 커서 페이지네이션이 이어지고 정렬 규칙이 지켜지는지를 검증MockMvc기반으로 인증/CSRF를 포함한 요청 흐름과 DB 반영까지 확인📊 변경 효과 요약 (가능한 경우에만)
ReviewControllerTest(492 lines)ReviewControllerIntegrationTest(349 lines)ReviewServiceTest(340 lines)ReviewRepositoryTest(319 lines)Lines changed합산 기준)