Skip to content

Conversation

@HoyeongJeon
Copy link
Collaborator

@HoyeongJeon HoyeongJeon commented May 28, 2025

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📝 작업 내용

  • Comment 도메인 테스트 작성

✏️ 관련 이슈


🎸 기타 사항 or 추가 코멘트

Summary by CodeRabbit

  • 테스트

    • MockK로 테스트 프레임워크를 전환하여 테스트 코드의 명확성과 일관성을 개선했습니다.
    • 댓글 삭제 및 예외 상황에 대한 테스트가 추가되어 테스트 커버리지가 향상되었습니다.
    • 서비스 레이어의 다양한 메서드에 대한 성공 및 실패 케이스 테스트가 보강되었습니다.
  • Chores

    • GitHub Actions 워크플로우가 main 브랜치로의 풀 리퀘스트에도 동작하도록 트리거가 확장되었습니다.

@HoyeongJeon HoyeongJeon self-assigned this May 28, 2025
@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

Walkthrough

테스트 코드에서 Mockito를 MockK로 전환하고, 주석 및 예외 검증을 강화하며, 삭제 기능에 대한 테스트를 추가했습니다. GitHub Actions 워크플로우는 main 브랜치로의 pull request 이벤트에도 트리거되도록 수정되었습니다.

Changes

파일/경로 변경 요약
.github/workflows/deploy.yml 워크플로우 트리거에 pull_request(main) 이벤트 추가
src/test/kotlin/gomushin/backend/schedule/domain/facade/... UpsertAndDeleteCommentFacadeTest: Mockito → MockK, 삭제 테스트 추가, 예외 검증 강화
src/test/kotlin/gomushin/backend/schedule/domain/service/... CommentServiceTest: Mockito → MockK, 테스트 케이스 확장 및 예외 검증 추가

Possibly related PRs

  • Issue: (#31) 편지 및 댓글 CUD #32: 댓글 및 편지의 생성, 수정, 삭제(CUD) 기능을 구현하고 관련 서비스, 엔티티, 리포지토리, 파사드, 컨트롤러 및 테스트를 추가한 PR로, 이번 PR의 테스트 리팩토링 및 추가와 직접적으로 연관됩니다.

Suggested reviewers

  • kimyeoungrok

Poem

🐰
MockK로 바꾼 테스트 밤,
예외도 꼼꼼히 잡아낸다람!
워크플로우도 PR에 반응해,
코드 토끼는 신나게 춤추네.
테스트 커버리지 쑥쑥,
오늘도 코드밭에 평화가 쭉쭉!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52bdf38 and 4d2bd6a.

📒 Files selected for processing (3)
  • .github/workflows/deploy.yml (1 hunks)
  • src/test/kotlin/gomushin/backend/schedule/domain/facade/UpsertAndDeleteCommentFacadeTest.kt (2 hunks)
  • src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Sarang Backend CI/CD
src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt

[error] 494-494: Test failure in 'getById - 존재하지 않는 id로 조회 시 BadRequestException 발생'. org.opentest4j.AssertionFailedError caused by io.mockk.MockKException at line 176.


[error] 440-440: Test failure in '업데이트 실패 - 작성자가 일치하지 않을 때'. org.opentest4j.AssertionFailedError caused by io.mockk.MockKException at line 108.

🔇 Additional comments (12)
.github/workflows/deploy.yml (1)

6-7: PR 검증을 위한 트리거 추가가 적절합니다

pull request 이벤트 트리거를 추가하여 PR 검증 시에도 CI/CD 파이프라인이 실행되도록 한 것은 좋은 개선사항입니다. 이를 통해 메인 브랜치로 병합하기 전에 테스트와 빌드를 확인할 수 있습니다.

src/test/kotlin/gomushin/backend/schedule/domain/facade/UpsertAndDeleteCommentFacadeTest.kt (7)

29-29: MockK 마이그레이션이 적절하게 수행되었습니다

Mockito에서 MockK로의 마이그레이션이 올바르게 적용되었습니다. @ExtendWith(MockKExtension::class) 사용이 적절합니다.


46-52: SpringContextHolder 모킹 설정이 적절합니다

@BeforeEach에서 SpringContextHolderAppEnv를 모킹하는 설정이 올바르게 구현되었습니다. 테스트 환경에서 일관된 환경 ID를 제공합니다.


54-56: customUserDetails 초기화가 적절합니다

init 블록에서 customUserDetails의 ID를 고정값으로 설정한 것이 테스트의 일관성을 보장합니다.


75-83: MockK의 every 블록 사용이 적절합니다

commentService.upsert 메서드 호출에 대한 모킹이 eq() 매처와 함께 올바르게 구현되었습니다. 매개변수 검증이 정확합니다.


106-134: delete 기능 테스트가 잘 작성되었습니다

새로 추가된 delete 테스트가 필요한 모든 서비스 호출을 모킹하고 검증하고 있습니다. 테스트 로직이 명확하고 적절합니다.


136-162: 권한 검증 테스트가 적절합니다

작성자가 아닌 사용자의 삭제 시도를 테스트하는 로직이 올바르게 구현되었습니다. 예외 메시지 검증도 포함되어 있습니다.


164-190: letterId 불일치 검증 테스트가 적절합니다

편지 ID가 일치하지 않는 경우의 예외 처리 테스트가 올바르게 구현되었습니다. 에러 메시지 검증이 포함되어 있어 좋습니다.

src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt (4)

25-26: MockK 마이그레이션이 적절하게 수행되었습니다

Mockito에서 MockK로의 마이그레이션이 올바르게 적용되었습니다. @ExtendWith(MockKExtension::class) 사용이 적절합니다.


34-40: SpringContextHolder 모킹 설정이 적절합니다

@BeforeEach에서 SpringContextHolderAppEnv를 모킹하는 설정이 다른 테스트 파일과 일관되게 구현되었습니다.


183-199: findAllByLetter 테스트가 적절합니다

Letter 엔티티를 모킹하고 repository 호출을 검증하는 테스트가 올바르게 구현되었습니다.


201-244: 삭제 관련 테스트들이 적절합니다

delete, deleteAllByMemberId, deleteAllByLetterId 메서드들에 대한 테스트가 모두 적절하게 구현되어 있습니다. repository 호출을 올바르게 검증하고 있습니다.

Comment on lines +94 to +121
@Test
fun update_failed_authorId_not_match() {
// given
val id = 1L
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
every { commentService.getById(id) } returns comment

@DisplayName("댓글 생성 성공")
@Test
fun insert_success() {
// given
val letterId = 1L
val authorId = 1L
val nickname = "닉네임"
val upsertCommentRequest = UpsertCommentRequest(
commentId = null,
content = "내용"
// when
val exception = assertThrows<BadRequestException> {
commentService.upsert(
id = id,
letterId = 1L,
authorId = 2L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)
val mockComment = mock(Comment::class.java)
}
val errorMessage = exception.error.element.message.resolved

// then
assertEquals("댓글은 작성자만 삭제하거나 업데이트 할 수 있어요.", errorMessage)

}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

테스트 실패 원인: MockK 설정 문제 해결 필요

파이프라인에서 이 테스트가 실패하고 있습니다. commentService.getById(id)를 모킹하는 것이 문제의 원인일 수 있습니다.

다음과 같이 수정하세요:

-        every { commentService.getById(id) } returns comment

이 라인을 제거하고 repository 모킹만 유지하세요. 서비스 클래스의 내부 메서드를 모킹하는 것은 좋지 않은 패턴입니다.

📝 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
fun update_failed_authorId_not_match() {
// given
val id = 1L
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
every { commentService.getById(id) } returns comment
@DisplayName("댓글 생성 성공")
@Test
fun insert_success() {
// given
val letterId = 1L
val authorId = 1L
val nickname = "닉네임"
val upsertCommentRequest = UpsertCommentRequest(
commentId = null,
content = "내용"
// when
val exception = assertThrows<BadRequestException> {
commentService.upsert(
id = id,
letterId = 1L,
authorId = 2L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)
val mockComment = mock(Comment::class.java)
}
val errorMessage = exception.error.element.message.resolved
// then
assertEquals("댓글은 작성자만 삭제하거나 업데이트 할 수 있어요.", errorMessage)
}
@Test
fun update_failed_authorId_not_match() {
// given
val id = 1L
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
// when
val exception = assertThrows<BadRequestException> {
commentService.upsert(
id = id,
letterId = 1L,
authorId = 2L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)
}
val errorMessage = exception.error.element.message.resolved
// then
assertEquals("댓글은 작성자만 삭제하거나 업데이트 할 수 있어요.", errorMessage)
}
🤖 Prompt for AI Agents
In
src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt
between lines 94 and 121, the test fails because commentService.getById(id) is
being mocked, which is an internal service method and should not be mocked.
Remove the mocking line for commentService.getById(id) and keep only the mocking
of commentRepository.findByIdOrNull(id) to fix the test.

Comment on lines +72 to +91
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
every { commentService.getById(id) } returns comment

// when
`when`(commentRepository.findById(id)).thenReturn(Optional.of(mockComment))
commentService.upsert(id, letterId, authorId, nickname, upsertCommentRequest)
// when
commentService.upsert(
id = id,
letterId = 1L,
authorId = 1L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)

// then
verify(mockComment).content = upsertCommentRequest.content
// then
verify { comment.content = "새 내용" }
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

MockK의 relaxUnitFun 사용과 모킹 순환 참조 문제

update_success 테스트에서 commentService.getById(id)를 모킹하고 있는데, 이는 테스트 대상 클래스 내부의 메서드를 모킹하는 것입니다. 이로 인해 순환 참조나 예상치 못한 동작이 발생할 수 있습니다.

다음과 같이 수정하는 것을 권장합니다:

-        every { commentService.getById(id) } returns comment

대신 commentRepository.findByIdOrNull(id)만 모킹하고, 실제 getById 메서드의 로직을 테스트하도록 변경하세요.

📝 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
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
every { commentService.getById(id) } returns comment
// when
`when`(commentRepository.findById(id)).thenReturn(Optional.of(mockComment))
commentService.upsert(id, letterId, authorId, nickname, upsertCommentRequest)
// when
commentService.upsert(
id = id,
letterId = 1L,
authorId = 1L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)
// then
verify(mockComment).content = upsertCommentRequest.content
// then
verify { comment.content = "새 내용" }
}
val comment = mockk<Comment>(relaxUnitFun = true) {
every { this@mockk.id } returns id
every { authorId } returns 1L
every { content } returns "기존 내용"
}
every { commentRepository.findByIdOrNull(id) } returns comment
// when
commentService.upsert(
id = id,
letterId = 1L,
authorId = 1L,
nickname = "작성자",
upsertCommentRequest = mockk { every { content } returns "새 내용" }
)
// then
verify { comment.content = "새 내용" }
}
🤖 Prompt for AI Agents
In
src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt
around lines 72 to 91, remove the mocking of commentService.getById(id) to avoid
circular reference issues. Instead, only mock
commentRepository.findByIdOrNull(id) and let the actual getById method execute
during the test to properly verify the logic without unintended side effects.

Comment on lines +167 to +181
@DisplayName("실패 - getById - 존재하지 않는 id로 조회 시 BadRequestException 발생")
@Test
fun getById_notFound() {
// given
val id = 1L
every { commentRepository.findByIdOrNull(id) } returns null

// when & then
val exception = assertThrows<BadRequestException> {
commentService.getById(id)
}
val errorMessage = exception.error.element.message.resolved

assertEquals("댓글을 찾을 수 없어요.", errorMessage)
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

테스트 실패 원인: getById 메서드 테스트 수정 필요

파이프라인에서 이 테스트가 실패하고 있습니다. MockKException이 발생하는 것으로 보아 모킹 설정에 문제가 있을 수 있습니다.

테스트가 실제로 getById 메서드를 호출하도록 하고, 예외가 올바르게 발생하는지 확인하세요. 현재 설정으로는 MockK가 예외를 올바르게 처리하지 못할 수 있습니다.

다음과 같이 검증 스크립트를 실행해서 실제 실패 원인을 파악하세요:


🏁 Script executed:

#!/bin/bash
# Description: MockK 관련 테스트 실패 원인 분석을 위해 CommentService 구현체 확인

# CommentService의 getById 메서드 구현 확인
ast-grep --pattern 'fun getById($PARAM): Comment {
  $$$
}'

# findByIdOrNull 사용 패턴 확인
rg -A 5 "findByIdOrNull" --type kotlin

Length of output: 19581


🏁 Script executed:

#!/bin/bash
# Inspect CommentService.kt implementation around getById
rg -n "class CommentService" -A30 -B5 --type kotlin src/main/kotlin

Length of output: 4002


🏁 Script executed:

#!/bin/bash
# CommentService의 getById 메서드 구현 확인
rg -n "fun getById" -C3 --type kotlin src/main/kotlin/gomushin/backend/schedule/domain/service/CommentService.kt

Length of output: 311


🏁 Script executed:

#!/bin/bash
# Show top of CommentServiceTest.kt
sed -n '1,30p' src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt

Length of output: 1214


테스트 실패 원인: Spring Data Extension 함수 findByIdOrNull 모킹 오류

commentRepository.findByIdOrNull(id)는 Kotlin 확장 함수이기 때문에 MockK가 기본적으로 인터셉트하지 못합니다.
따라서 every { commentRepository.findByIdOrNull(id) } … 로 스텁을 걸어도 실제 호출 시 예외(MockKException)가 발생합니다.

해결 방안:

  • 테스트 클래스 상단 또는 @BeforeEachmockkStatic("org.springframework.data.repository.findByIdOrNull") 추가
    @BeforeEach
    fun setUp() {
        mockkStatic("org.springframework.data.repository.findByIdOrNull")
    }
  • 스텁 구문을 확장 함수 호출 형태로 변경
    every { findByIdOrNull(commentRepository, id) } returns mockComment
  • 또는 확장 함수가 내부에서 호출하는 원본 메서드(findById)를 직접 스텁
    every { commentRepository.findById(id) } returns Optional.of(mockComment)  // 성공 케이스
    every { commentRepository.findById(id) } returns Optional.empty()         // 실패 케이스

추가 확인:

  • commentService@InjectMockKs로 제대로 주입되고 있는지 검증

[src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt]

  • 상단에 mockkStatic 추가
  • 기존 every { commentRepository.findByIdOrNull(id) }→위 제안 중 하나로 교체
🤖 Prompt for AI Agents
In
src/test/kotlin/gomushin/backend/schedule/domain/service/CommentServiceTest.kt
around lines 167 to 181, the test mocks the Kotlin extension function
findByIdOrNull on commentRepository, which MockK cannot intercept by default,
causing MockKException. To fix this, add
mockkStatic("org.springframework.data.repository.findByIdOrNull") in a
@BeforeEach setup method, then replace the stub from every {
commentRepository.findByIdOrNull(id) } to either every {
findByIdOrNull(commentRepository, id) } or mock the underlying
repository.findById method directly with every { commentRepository.findById(id)
} returning Optional.empty() for the failure case. Also verify that
commentService is properly injected with @InjectMockKs.

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