Skip to content

Conversation

qkrehgus02
Copy link
Collaborator

@qkrehgus02 qkrehgus02 commented Aug 16, 2025

📌 PR 제목

  • feat: 228 course 도메인 test code 작성

✅ 작업 내용

  • course 도메인의 service 파일에 대한 test code를 작성하였습니다.

Summary by CodeRabbit

  • Tests
    • CourseService에 대한 포괄적 단위 테스트 추가.
    • 코스 생성, 빈 생성, 조회(단건/페이지), 수정, 추천 흐름과 에러 메시지 검증.
    • 타입 필터링, 빈 결과 처리 등 다양한 케이스 커버.
    • 외부 연동 호출 여부 및 호출 횟수 확인으로 부수효과 점검.
    • 전반적 회귀 방지와 안정성 향상.

getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

updateCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

updateCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

getCoursePageByCourseType에 대한 2가지 케이스 검증에 대한 테스트코드 작성
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

updateCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

getCoursePageByCourseType에 대한 2가지 케이스 검증에 대한 테스트코드 작성

createCourse, createEmptyCourse에서 코스가 정상적으로 생겨나는지에 대한 테스트코드
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

updateCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

getCoursePageByCourseType에 대한 2가지 케이스 검증에 대한 테스트코드 작성

createCourse, createEmptyCourse에서 코스가 정상적으로 생겨나는지에 대한 테스트코드

getCourseById에서 각각 성공/실패 경우에 대한 테스트코드
getCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

updateCourse에 대하여 normal/empty 케이스에 대한 테스트코드 작성

getCoursePageByCourseType에 대한 2가지 케이스 검증에 대한 테스트코드 작성

createCourse, createEmptyCourse에서 코스가 정상적으로 생겨나는지에 대한 테스트코드

getCourseById에서 각각 성공/실패 경우에 대한 테스트코드

getRecommendedCourse의 성공/실패 경우에 대한 테스트코드
@qkrehgus02 qkrehgus02 linked an issue Aug 16, 2025 that may be closed by this pull request
Copy link

coderabbitai bot commented Aug 16, 2025

Walkthrough

CourseService에 대한 새로운 JUnit 5/Mockito 기반 단위 테스트 클래스가 추가되었으며, 생성/조회/업데이트/페이징/추천 및 예외 경로를 포함해 서비스 메서드 동작을 검증합니다. 리포지토리와 스크래핑 서비스는 목 처리되며, 테스트 유틸로 리플렉션을 사용해 엔티티 필드를 세팅합니다.

Changes

Cohort / File(s) Change Summary
Test: CourseService
src/test/java/com/aloc/aloc/course/service/CourseServiceTest.java
CourseService용 단위 테스트 신규 추가. Mockito 확장 사용, CourseRepository/ProblemScrapingService 목, 생성/빈 생성/업데이트/ID 조회/추천/페이징/예외 케이스 검증. 리플렉션 유틸과 코스 생성 헬퍼 포함.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10–15 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • soonga00

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 228-feat-course-도메인-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
🪧 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

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

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 0

🧹 Nitpick comments (9)
src/test/java/com/aloc/aloc/course/service/CourseServiceTest.java (9)

3-21: 중복/불필요한 import 정리 및 Mockito 통합 추천

  • 동일/중복 import: Optional(라인 6, 17), assertThatThrownBy(라인 8, 20)
  • Mockito 이중 import: mock, when 개별 + * 와일드카드 혼용
  • 사용되지 않는 import: eq, Objects
  • InOrder 검증 추가 시 org.mockito.InOrder 타입 import 필요

정리하면 가독성/유지보수성이 좋아지고, 일부 빌드/린트 환경에서 발생 가능한 “중복 import” 경고/실패를 예방합니다.

아래처럼 정리하는 것을 제안드립니다.

-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 import static org.assertj.core.api.Assertions.assertThat;
 import java.util.Optional;
 import java.util.NoSuchElementException;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.*;
 
 import com.aloc.aloc.algorithm.entity.Algorithm;
 import com.aloc.aloc.course.entity.CourseProblem;
 import com.aloc.aloc.problem.entity.Problem;
 import com.aloc.aloc.problem.entity.ProblemAlgorithm;
 import org.mockito.ArgumentCaptor;
 import java.io.IOException;
-import java.util.Optional;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import org.mockito.InOrder;
 
 import com.aloc.aloc.course.dto.request.CourseRequestDto;
 import com.aloc.aloc.course.dto.response.CourseResponseDto;
 import com.aloc.aloc.course.entity.Course;
 import com.aloc.aloc.course.enums.CourseType;
 import com.aloc.aloc.course.enums.UserCourseState;
 import com.aloc.aloc.course.repository.CourseRepository;
 import com.aloc.aloc.scraper.ProblemScrapingService;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 
 import java.util.List;
-import java.util.Objects;

Also applies to: 39-41


49-81: 테스트 픽스처 리플렉션 의존도 축소 제안

stubCourseWithOf에서 calculateAverageRank 호출을 리플렉션으로 탐색/호출하고, 없으면 필드를 직접 주입하고 있습니다. 현재 이 헬퍼를 사용하는 테스트에서는 averageRank를 단언하지 않으므로 이 블록은 불필요하게 복잡합니다. 단순화를 추천합니다.

아래처럼 averageRank 관련 리플렉션 블록을 제거해도 현 테스트 의도에는 영향이 없습니다.

   // 2) 실제 팩토리로 Course 생성
   Course course = Course.of(req);

-  // 3) averageRank 보장: calculateAverageRank() 있으면 호출, 없으면 직접 세팅
-  try {
-    var m = Course.class.getDeclaredMethod("calculateAverageRank");
-    m.setAccessible(true);
-    m.invoke(course);
-  } catch (NoSuchMethodException e) {
-    // 메소드가 없으면 (min+max)/2로 직접 주입
-    int avg = (minRank + maxRank) / 2;
-    setFieldQuiet(course, "averageRank", Integer.valueOf(avg));
-  } catch (ReflectiveOperationException e) {
-    throw new AssertionError("averageRank 계산 호출 실패", e);
-  }

추가로, 프로젝트에 공용 테스트 픽스처(예: TestFixture)나 빌더가 있다면 이를 활용해 리플렉션 사용을 더 줄이는 것도 고려해보세요.


118-132: 테스트 메서드명 오타 수정 제안 (Empry → Empty)

오타로 인한 혼동을 줄이기 위해 메서드명을 정정하는 것을 권장합니다.

-void getCourseEmpryCase(){
+void getCourseEmptyCase(){

134-147: updateCourse 동작 검증 강화: 엔티티 메서드 호출 검증 추가

서비스 로직상 course.updateRankRange() 호출이 핵심인데, 현재 호출 여부 검증이 없습니다. 모킹된 Course로 호출 여부를 검증하면 리그레션을 방지할 수 있습니다.

   //then
   assertThat(updated).isSameAs(mockCourse);
+  verify(mockCourse, times(1)).updateRankRange();

202-230: 생성 후 스크래핑 순서 보장 검증 추가 제안

주석으로 의도가 명시되어 있지만, 실제로 save → 스크래핑 호출 순서를 단언하지는 않습니다. InOrder를 사용해 호출 순서를 검증하면 요구사항을 명확히 담보할 수 있습니다.

   Course saved = captor.getValue();

   assertThat(created).isSameAs(saved);
   verify(problemScrapingService, times(1)).createProblemsByCourse(saved, req);
   verifyNoMoreInteractions(problemScrapingService);
   //코스를 생성하여 save 한 후 순차적으로 스크래핑이 이어져야함.
+
+  // 호출 순서(save → createProblemsByCourse) 보장
+  InOrder inOrder = inOrder(courseRepository, problemScrapingService);
+  inOrder.verify(courseRepository).save(any(Course.class));
+  inOrder.verify(problemScrapingService).createProblemsByCourse(saved, req);

232-256: 테스트 메서드 네이밍 컨벤션 정렬(lowerCamelCase)

다른 메서드와 컨벤션을 맞추면 가독성이 좋아집니다.

-void CreateEmptyCourseNormalCase(){
+void createEmptyCourseNormalCase(){

273-285: 예외 메시지 단언을 contains로 완화하여 변경 내성 개선 제안

정확 일치보다 포함 단언이 메시지 포맷 변경에 더 견고합니다. 위의 updateCourseEmptyCase와도 일관화됩니다.

-  .hasMessage("해당 코스 아이디로 된 코스가 존재하지 않습니다.");
+  .hasMessageContaining("해당 코스 아이디로 된 코스가 존재하지 않습니다.");

287-314: 추천 코스 테스트 메서드명 복수형으로 통일 제안

서비스 메서드명이 getRecommendedCourses(복수)인 만큼 테스트 메서드명도 복수형으로 맞추면 일관성이 좋아집니다.

-void getRecommendedCourseSuccessCase(){
+void getRecommendedCoursesSuccessCase(){
...
-void getRecommendedCourseEmptyCase() {
+void getRecommendedCoursesEmptyCase() {

Also applies to: 316-343


42-47: 커버리지 보강 제안: 활성 코스 수/목록 조회 테스트 추가

CourseService의 아래 메서드에 대한 간단 테스트가 있으면 커버리지가 더 견고해집니다.

  • getActiveCourseCount(): courseRepository.count() 위임 검증
  • getActiveCourses(): courseRepository.findAll() 위임 검증

원하시면 해당 테스트 케이스 템플릿을 바로 추가해드리겠습니다.

Also applies to: 345-346

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6e0a53b and 8f79808.

📒 Files selected for processing (1)
  • src/test/java/com/aloc/aloc/course/service/CourseServiceTest.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/test/java/com/aloc/aloc/course/service/CourseServiceTest.java (2)
src/test/java/com/aloc/aloc/course/controller/CourseControllerTest.java (1)
  • CourseControllerTest (26-70)
src/main/java/com/aloc/aloc/course/service/CourseService.java (1)
  • CourseService (20-83)
🔇 Additional comments (6)
src/test/java/com/aloc/aloc/course/service/CourseServiceTest.java (6)

83-91: 리플렉션 유틸은 간결하고 목적에 부합합니다

테스트 전용 필드 주입 유틸이 명확하고, 실패 시 AssertionError로 전파하는 처리도 적절합니다.


93-116: getCourses 기본 플로우(비로그인) 검증: 적절합니다

페이지 결과/정렬 유지, 상태 매핑(NOT_STARTED)까지 확인되어 신뢰도 좋습니다.


149-161: 예외 플로우 및 부수효과 차단 검증: 적절합니다

미존재 케이스에서 메시지, findById 호출/ save 미호출까지 단언되어 있습니다.


163-181: 코스 타입 null 분기 테스트: 적절합니다

리포지토리 위임과 상호작용 검증이 명확합니다.


183-200: 코스 타입 지정 분기 테스트: 적절합니다

정해진 메서드 호출만 발생하는지 검증되어 있습니다.


258-271: getCourseById 성공 케이스: 적절합니다

정상 플로우와 상호작용이 잘 검증되어 있습니다.

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.

Feat: course 도메인 test code 작성
1 participant