Skip to content

unit test baseline과 서비스 계층 테스트 도입#87

Merged
alexization merged 2 commits into
developfrom
test/86-backend-unit-test-baseline
Apr 14, 2026
Merged

unit test baseline과 서비스 계층 테스트 도입#87
alexization merged 2 commits into
developfrom
test/86-backend-unit-test-baseline

Conversation

@alexization
Copy link
Copy Markdown
Owner

@alexization alexization commented Apr 14, 2026

1) 요약

  • 무엇이 변경되었나요?
    • backend unit test baseline을 복구하고 src/test/**에 pure component + domain service 계층 unit test를 추가했습니다.
    • CI / deploy verify 단계에 ./gradlew test를 넣고 packaging build는 ./gradlew build -x test로 분리했습니다.
    • locale / wall-clock 의존을 줄이기 위해 badge formatting과 일부 time-dependent path에 최소 seam을 추가했습니다.
  • 왜 지금 필요한가요?
    • 현재 backend는 build-only 검증이라 비즈니스 service 회귀를 물리적 gate에서 잡지 못했습니다.

2) 연관 이슈

3) 문제와 목표

  • 문제:
    • git-ranker는 test runtime과 src/test/ tree가 없어 backend 변경이 ./gradlew build만으로 검증되고 있었습니다.
  • 사용자/운영자 관점의 결과:
    • pure component와 핵심 domain service branch가 unit test로 고정되고, verify 단계가 회귀를 더 일찍 잡습니다.
  • 비목표:
    • integration test / Testcontainers lane 복구
    • controller / security / batch / infrastructure 계층 테스트 추가

4) 영향 범위

  • 변경된 패키지/모듈:
    • domain.badge
    • domain.auth.service
    • domain.log
    • domain.ranking
    • domain.user.service
    • global.util
    • src/test/**
    • build.gradle, .github/workflows/*, AGENTS.md
  • API/DTO/Schema 영향:
    • 없음
  • DB/Cache/Batch/Scheduler 영향:
    • runtime schema 변경 없음
    • verify workflow에서 unit-test gate가 추가됨
  • 보안/권한 영향:
    • 없음

5) 검증 증거

유형 명령어 / 증거 결과
Build ./gradlew build 통과
Unit ./gradlew test 통과
Integration 미실행(이번 spec 범위에서 제외) 생략
Coverage 미실행(coverage gate는 이번 spec 비범위) 생략
API/Manual Smoke 미실행(unit-test baseline 작업) 생략

6) 관측성 확인

  • 확인한 로그:
    • unit-test baseline 작업이라 별도 runtime log 확인 없음
  • 확인한 메트릭:
    • 없음
  • 확인한 trace/dashboard/query:
    • 없음

7) AI 리뷰 메모 (선택)

  • Codex:
    • latest verification 기준 ./gradlew test, ./gradlew build 통과
  • CodeRabbitAI:
    • 없음

8) 리스크 및 롤백

  • 리스크:
    • 일부 service 영역의 cookie/header, response mapping assertion 깊이는 여전히 균일하지 않습니다.
    • future에 check에 새 검증이 묶이면 workflow의 build -x test 사용 여부를 다시 점검해야 합니다.
  • 롤백 계획:
    • test baseline 도입 전 상태로 build.gradle, workflow, AGENTS.md, src/test/**를 되돌립니다.

9) 체크리스트

  • 연관 이슈가 연결되어 있음
  • Build / Unit / Integration 결과가 기입되어 있음
  • API/스키마/배치 영향이 반영되었거나 없음을 명시함
  • 로그/메트릭/trace 확인 내용을 적었거나 불필요 사유를 적음
  • 문서 또는 후속 이슈가 업데이트되었거나 불필요 사유를 적음

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 배지 포맷팅에서 로케일별 숫자 형식 처리 개선으로 일관된 표시 보장
  • 테스트

    • 인증, 배지, 사용자, 순위 및 기타 핵심 기능에 대한 포괄적인 단위 테스트 추가
  • Chores

    • CI/CD 워크플로우 최적화 (테스트 단계 분리)
    • 테스트 의존성 및 빌드 구성 업데이트

- unit test runtime과 workflow verification baseline 정렬
- pure component와 domain service 계층 테스트 추가
- locale 및 wall-clock 의존을 줄이는 최소 seam 보강
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 456e8408-3311-48c5-bd6e-ff84952d5b6a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

단위 테스트 기반을 복구하기 위해 CI/배포 워크플로우를 ./gradlew test./gradlew build -x test로 분리하고, JUnit Platform 의존성을 추가한 뒤, 20개 이상의 서비스 계층 단위 테스트를 도입하며, 로케일 및 시간대 독립성을 위한 프로덕션 코드 개선을 수행합니다.

Changes

Cohort / File(s) Summary
CI/배포 워크플로우
.github/workflows/ci.yml, .github/workflows/deploy.yml
작업명을 "Test and Build Verification"으로 변경하고, 단일 ./gradlew build 대신 ./gradlew test 실행 후 ./gradlew build -x test로 테스트 재실행을 방지합니다.
빌드 설정
build.gradle
Spring Boot starter-test, JUnit Platform launcher를 testImplementation/testRuntimeOnly에 추가하고, tasks.named('test') { useJUnitPlatform() } 구성을 추가합니다.
문서화
AGENTS.md
단위 테스트 기반을 명시하고 검증 흐름을 ./gradlew test./gradlew build -x test로 정렬하며, baseline 변경 기준을 src/test/ 및 test 의존성 점검으로 업데이트합니다.
로케일/시간대 개선
src/main/java/com/gitranker/api/domain/badge/BadgeFormatter.java, src/main/java/com/gitranker/api/domain/badge/SvgBadgeRenderer.java, src/main/java/com/gitranker/api/domain/badge/BadgeService.java, src/main/java/com/gitranker/api/domain/user/service/BaselineStatsCalculator.java
Locale.US/Locale.ROOT을 명시적으로 적용하고, 시간 의존성을 주입 가능한 currentDate() 메서드로 분리합니다.
인증 서비스 테스트
src/test/java/com/gitranker/api/domain/auth/service/AuthServiceTest.java, src/test/java/com/gitranker/api/domain/auth/service/RefreshTokenServiceTest.java
refresh token 발급, 만료/무효화 처리, 로그아웃 및 세션 정리에 대한 6개 테스트 케이스를 추가합니다.
배지 관련 테스트
src/test/java/com/gitranker/api/domain/badge/BadgeFormatterTest.java, src/test/java/com/gitranker/api/domain/badge/BadgeServiceTest.java, src/test/java/com/gitranker/api/domain/badge/SvgBadgeRendererTest.java, src/test/java/com/gitranker/api/domain/badge/TierGradientProviderTest.java
숫자 포맷팅, 차이 표시, tier 이름, SVG 렌더링 및 gradient 색상에 대한 테스트를 추가합니다.
활동 로그/실패 로그 테스트
src/test/java/com/gitranker/api/domain/log/ActivityLogServiceTest.java, src/test/java/com/gitranker/api/domain/failure/BatchFailureLogServiceTest.java
활동 로그 저장, 업데이트, 조회 및 배치 실패 로깅 처리를 검증합니다.
랭킹 서비스 테스트
src/test/java/com/gitranker/api/domain/ranking/RankingRecalculationServiceTest.java, src/test/java/com/gitranker/api/domain/ranking/RankingServiceTest.java
랭킹 재계산 debounce 로직 및 tier/전체 랭킹 조회 동작을 검증합니다.
사용자 서비스 테스트
src/test/java/com/gitranker/api/domain/user/service/BaselineStatsCalculatorTest.java, src/test/java/com/gitranker/api/domain/user/service/UserDeletionServiceTest.java, src/test/java/com/gitranker/api/domain/user/service/UserPersistenceServiceTest.java, src/test/java/com/gitranker/api/domain/user/service/UserQueryServiceTest.java, src/test/java/com/gitranker/api/domain/user/service/UserRefreshServiceTest.java, src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java
사용자 조회, 생성, 프로필 업데이트, 통계 갱신, 삭제, 새로고침 및 baseline 통계 계산을 포함한 사용자 도메인 전반의 서비스 계층 테스트를 추가합니다.
유틸리티 테스트 및 지원
src/test/java/com/gitranker/api/global/util/TimeUtilsTest.java, src/test/java/com/gitranker/api/support/TestFixtures.java
시간대 변환, 포맷팅을 검증하고, 도메인 객체 생성을 위한 공유 테스트 fixture를 제공합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

enhancement, testing, backend, unit-tests

Poem

🐰 시험 없던 날들이 가고,
이제 테스트로 다지는 기초,
Mockito 마법으로 검증된 로직,
배포도 안심, 회귀는 NO—
단위테스트의 봄이 왔도다! 🌱✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed PR은 연결된 이슈 #86의 모든 주요 목표를 충족합니다: build.gradle 테스트 런타임 추가, CI/배포 workflow 정렬, AGENTS.md 문서화, src/test/**에 단위 테스트 추가, 로케일/시간 의존성 감소를 위한 seam 보강.
Out of Scope Changes check ✅ Passed 모든 변경사항이 명시된 범위 내에 있습니다. 통합 테스트, controller/security/batch 계층 테스트, API/스키마 변경은 제외되었으며, 순수 컴포넌트 및 도메인 서비스 계층 테스트만 추가되었습니다.
Title check ✅ Passed 제목은 PR의 주요 변경사항(unit test baseline과 서비스 계층 테스트 도입)을 명확하게 요약하고 있으며, 제공된 파일 변경 사항들과 일치합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/86-backend-unit-test-baseline

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 and usage tips.

@alexization alexization changed the title 백엔드 unit test baseline과 서비스 계층 테스트 도입 unit test baseline과 서비스 계층 테스트 도입 Apr 14, 2026
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (8)
src/test/java/com/gitranker/api/domain/auth/service/RefreshTokenServiceTest.java (1)

44-45: 삭제→저장 호출 순서도 고정해두는 편이 안전합니다.

현재는 두 호출의 “존재”만 검증해서 순서가 바뀌어도 테스트가 통과합니다. 순서 역전 회귀(새 토큰까지 삭제)를 막기 위해 순서 검증을 추가하는 것을 권장합니다.

제안 diff
@@
-        verify(refreshTokenRepository).deleteAllByUser(user);
-        verify(refreshTokenRepository).save(any(RefreshToken.class));
+        org.mockito.InOrder order = org.mockito.Mockito.inOrder(refreshTokenRepository);
+        order.verify(refreshTokenRepository).deleteAllByUser(user);
+        order.verify(refreshTokenRepository).save(any(RefreshToken.class));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/gitranker/api/domain/auth/service/RefreshTokenServiceTest.java`
around lines 44 - 45, The test currently only verifies that
refreshTokenRepository.deleteAllByUser(user) and
refreshTokenRepository.save(any(RefreshToken.class)) were called but not their
order; update RefreshTokenServiceTest to enforce call order by creating an
InOrder for refreshTokenRepository (e.g., InOrder inOrder =
inOrder(refreshTokenRepository)) and use
inOrder.verify(refreshTokenRepository).deleteAllByUser(user) followed by
inOrder.verify(refreshTokenRepository).save(any(RefreshToken.class)); keep or
remove the existing unordered verify(...) assertions as desired.
src/test/java/com/gitranker/api/domain/badge/SvgBadgeRendererTest.java (1)

31-41: diff 렌더링은 음수 케이스도 함께 고정해두는 것이 좋습니다.

Line 27에서 음수 diff 데이터를 넣고 있으므로, Line 31-41 assertion에 diff-minus/음수 표기까지 추가하면 렌더링 회귀를 더 잘 잡을 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/com/gitranker/api/domain/badge/SvgBadgeRendererTest.java`
around lines 31 - 41, The assertions in SvgBadgeRendererTest currently only
check for positive diff rendering ("diff-plus" and "+5") but the test setup
includes negative diff data; update the assertion block that checks the rendered
svg (the chained assertThat(svg).contains(...)) to also assert the negative diff
rendering by including "diff-minus" and the negative value string (e.g., "-5")
so the test covers both plus and minus diff cases.
src/test/java/com/gitranker/api/domain/user/service/BaselineStatsCalculatorTest.java (1)

33-40: 중복된 spy/날짜 고정 setup은 헬퍼로 추출하는 편이 좋습니다.

Line 33-40과 Line 52-64의 패턴이 동일해서, 고정 날짜 기반 BaselineStatsCalculator 생성 로직을 메서드로 빼면 테스트 의도가 더 선명해집니다.

예시 리팩터링
+    private BaselineStatsCalculator calculatorWithDate(LocalDate fixedDate) {
+        BaselineStatsCalculator calculator = Mockito.spy(new BaselineStatsCalculator(gitHubDataMapper));
+        Mockito.doReturn(fixedDate).when(calculator).currentDate();
+        return calculator;
+    }
+
     void calculatesBaselineForExistingUsers() {
-        BaselineStatsCalculator calculator = Mockito.spy(new BaselineStatsCalculator(gitHubDataMapper));
+        BaselineStatsCalculator calculator = calculatorWithDate(LocalDate.of(2026, 1, 1));
         ...
-        LocalDate fixedDate = LocalDate.of(2026, 1, 1);
+        LocalDate fixedDate = LocalDate.of(2026, 1, 1);
-        Mockito.doReturn(fixedDate).when(calculator).currentDate();
         ...
     }

Also applies to: 52-64

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/gitranker/api/domain/user/service/BaselineStatsCalculatorTest.java`
around lines 33 - 40, Extract the duplicated spy-and-fixed-date setup into a
private helper method (e.g., createCalculatorWithFixedDate or
setupCalculatorWithDate) that constructs the BaselineStatsCalculator spy, stubs
currentDate() via Mockito.doReturn(fixedDate).when(calculator).currentDate(),
and returns the prepared spy (and any commonly used fixtures like the fixed
LocalDate or User/ActivityStatistics via overloaded helpers if needed); then
replace the repeated blocks that create the BaselineStatsCalculator, call
Mockito.doReturn(...).when(calculator).currentDate(), and set up user(...) and
stats(...) with calls to this helper to remove duplication and clarify intent.
src/test/java/com/gitranker/api/domain/user/service/UserPersistenceServiceTest.java (1)

108-113: 통계 갱신 성공 케이스에 영속화 호출 검증을 추가해 주세요.

현재는 값 변경과 오케스트레이션 호출만 확인합니다. userRepository.save(...) 검증을 추가하면 저장 누락 회귀까지 막을 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserPersistenceServiceTest.java`
around lines 108 - 113, Add a verification that the repository persist call
happened: in UserPersistenceServiceTest after calling
updateUserStatisticsWithLog(1L, totalStats, baselineStats) and after the
existing verifies for activityLogOrchestrator and rankingRecalculationService,
add a verify on the mocked userRepository that save(...) was called (e.g.,
verify(userRepository).save(...) or verify(userRepository).save(same(user))
using the existing user test fixture) to ensure the persistence path in
updateUserStatisticsWithLog is exercised.
src/test/java/com/gitranker/api/domain/user/service/UserRefreshServiceTest.java (1)

92-95: 성공 경로에서는 rawResponse를 null 대신 명시 객체로 두는 편이 안전합니다.

현재 null 기반 스텁은 통과는 되지만, 실제 호출 계약이 바뀌어도 테스트가 의도를 놓칠 수 있습니다. mock 또는 fixture 응답 객체를 두고 연결하는 구성이 더 견고합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserRefreshServiceTest.java`
around lines 92 - 95, Replace the null-based stubbing with a concrete fixture
for the raw GitHub response: create a mock or fixture object (e.g., rawResponse)
and use it in the when(...) for
gitHubActivityService.fetchRawAllActivities("alice", user.getGithubCreatedAt())
instead of null, then update the dependent stubs to reference that same
rawResponse (gitHubDataMapper.toActivityStatistics(rawResponse) and
baselineStatsCalculator.calculate(user, rawResponse)) while keeping the final
updateUserStatisticsWithLog(1L, totalStats, baselineStats) stub unchanged; this
ensures the test exercises a realistic non-null contract for
fetchRawAllActivities and remains robust to API changes.
src/test/java/com/gitranker/api/domain/badge/BadgeServiceTest.java (1)

56-65: USER_NOT_FOUND 경로에 부수효과 부재 검증을 추가하는 것을 권장합니다.

예외 발생 시 businessMetrics/svgBadgeRenderer가 호출되지 않음을 함께 검증하면 실패 경로 회귀를 더 잘 방지할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/com/gitranker/api/domain/badge/BadgeServiceTest.java` around
lines 56 - 65, Update the test throwsWhenUserDoesNotExist in BadgeServiceTest to
also assert that failure-side collaborators are not called: after stubbing
userRepository.findByNodeId("missing") to return Optional.empty() and asserting
badgeService.generateBadge("missing") throws USER_NOT_FOUND, add verifications
that businessMetrics and svgBadgeRenderer were not invoked (e.g.,
verifyNoInteractions(svgBadgeRenderer) and verifyNoInteractions(businessMetrics)
or verify(svgBadgeRenderer, never()).render... / verify(businessMetrics,
never()).increment... as appropriate) so the USER_NOT_FOUND path has no side
effects.
src/test/java/com/gitranker/api/support/TestFixtures.java (1)

47-53: 반복되는 날짜/식별자 리터럴은 상수로 추출해 drift를 줄여주세요.

Line 48, Line 52, Line 65-67, Line 70의 하드코딩 값이 중복되어 이후 수정 시 테스트 간 불일치가 생기기 쉽습니다. 파일 상단 상수로 모아두는 편이 안전합니다.

예시 리팩터링 diff
 public final class TestFixtures {
+    private static final LocalDate FIXED_ACTIVITY_DATE = LocalDate.of(2025, 1, 1);
+    private static final int FIXED_GITHUB_ID = 12345;
+    private static final String FIXED_GITHUB_NODE_ID = "MDQ6VXNlcjEyMzQ1";
+    private static final String FIXED_GITHUB_CREATED_AT = "2020-01-01T00:00:00Z";
 
     private TestFixtures() {
     }
@@
     public static ActivityLog emptyActivityLog(User user) {
-        return ActivityLog.empty(user, LocalDate.of(2025, 1, 1));
+        return ActivityLog.empty(user, FIXED_ACTIVITY_DATE);
     }
@@
     public static ActivityLog activityLog(User user, ActivityStatistics totals, ActivityStatistics diff) {
-        return ActivityLog.of(user, totals, diff, LocalDate.of(2025, 1, 1));
+        return ActivityLog.of(user, totals, diff, FIXED_ACTIVITY_DATE);
     }
@@
     public static OAuthAttributes oauthAttributes(String username, String email, String profileImage) {
         Map<String, Object> attributes = new HashMap<>();
-        attributes.put("id", 12345);
-        attributes.put("node_id", "MDQ6VXNlcjEyMzQ1");
+        attributes.put("id", FIXED_GITHUB_ID);
+        attributes.put("node_id", FIXED_GITHUB_NODE_ID);
@@
-        attributes.put("created_at", "2020-01-01T00:00:00Z");
+        attributes.put("created_at", FIXED_GITHUB_CREATED_AT);
         return OAuthAttributes.of("id", attributes);
     }
 }

Also applies to: 63-71

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/com/gitranker/api/support/TestFixtures.java` around lines 47 -
53, Extract the hardcoded repeated literals used in TestFixtures (e.g., the
LocalDate.of(2025, 1, 1) in emptyActivityLog and activityLog and any repeated
identifier literals referenced around lines 63-71) into private static final
constants at the top of the class (e.g., TEST_DATE and any repeated IDs/names),
then replace the inline calls in ActivityLog.empty, ActivityLog.of and related
helper methods with those constants so all tests share the same single source of
truth.
src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java (1)

95-100: 기존 사용자 시나리오의 응답 단언 깊이를 맞춰주세요.

Line 95-100, Line 122-124에서 일부 필드만 단언하고 있어 response 매핑 회귀를 놓칠 수 있습니다. userId, commitCount, isNewUser까지 함께 검증하면 테스트 일관성이 좋아집니다.

Also applies to: 122-124

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java`
around lines 95 - 100, In UserRegistrationServiceTest, extend the assertions on
the existing "existing user" scenario to cover all relevant response fields so
mapping regressions are caught: after asserting response.username(),
response.isNewUser(), response.email(), and response.profileImage(), also assert
response.userId() and response.commitCount() (and keep response.isNewUser()
assertion) to match the expected values for an existing user; ensure the same
additional assertions are added in the other case mentioned (lines 122-124).
Leave the existing verify(...) checks for
gitHubActivityService.fetchRawAllActivities(...) and
businessMetrics.incrementRegistrations() intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/test/java/com/gitranker/api/domain/auth/service/AuthServiceTest.java`:
- Around line 36-37: The hard-coded expiry constants VALID_EXPIRY and EXPIRED_AT
in AuthServiceTest make tests brittle; change them to be relative to the current
time (e.g., use LocalDateTime.now().plus... for a valid future expiry and
LocalDateTime.now().minus... for an expired time) so tests like
refreshesAccessTokenForValidRefreshToken and any other assertions using
VALID_EXPIRY/EXPIRED_AT do not break with real-world calendar drift.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java`:
- Around line 64-66: The test stubs use nulls which can hide regressions; change
the fetchRawAllActivities and related mapper stub to use a non-null empty
collection (e.g., Collections.emptyList() or List.of()) instead of null, update
the gitHubDataMapper.toActivityStatistics stub to accept that empty collection,
and change the baselineStatsCalculator.calculate matcher from
org.mockito.ArgumentMatchers.isNull() to a matcher that expects the empty
collection (e.g., eq(Collections.emptyList()) or anyList()) so the data path
(gitHubActivityService.fetchRawAllActivities ->
gitHubDataMapper.toActivityStatistics -> baselineStatsCalculator.calculate) is
exercised with a real, non-null value.

---

Nitpick comments:
In
`@src/test/java/com/gitranker/api/domain/auth/service/RefreshTokenServiceTest.java`:
- Around line 44-45: The test currently only verifies that
refreshTokenRepository.deleteAllByUser(user) and
refreshTokenRepository.save(any(RefreshToken.class)) were called but not their
order; update RefreshTokenServiceTest to enforce call order by creating an
InOrder for refreshTokenRepository (e.g., InOrder inOrder =
inOrder(refreshTokenRepository)) and use
inOrder.verify(refreshTokenRepository).deleteAllByUser(user) followed by
inOrder.verify(refreshTokenRepository).save(any(RefreshToken.class)); keep or
remove the existing unordered verify(...) assertions as desired.

In `@src/test/java/com/gitranker/api/domain/badge/BadgeServiceTest.java`:
- Around line 56-65: Update the test throwsWhenUserDoesNotExist in
BadgeServiceTest to also assert that failure-side collaborators are not called:
after stubbing userRepository.findByNodeId("missing") to return Optional.empty()
and asserting badgeService.generateBadge("missing") throws USER_NOT_FOUND, add
verifications that businessMetrics and svgBadgeRenderer were not invoked (e.g.,
verifyNoInteractions(svgBadgeRenderer) and verifyNoInteractions(businessMetrics)
or verify(svgBadgeRenderer, never()).render... / verify(businessMetrics,
never()).increment... as appropriate) so the USER_NOT_FOUND path has no side
effects.

In `@src/test/java/com/gitranker/api/domain/badge/SvgBadgeRendererTest.java`:
- Around line 31-41: The assertions in SvgBadgeRendererTest currently only check
for positive diff rendering ("diff-plus" and "+5") but the test setup includes
negative diff data; update the assertion block that checks the rendered svg (the
chained assertThat(svg).contains(...)) to also assert the negative diff
rendering by including "diff-minus" and the negative value string (e.g., "-5")
so the test covers both plus and minus diff cases.

In
`@src/test/java/com/gitranker/api/domain/user/service/BaselineStatsCalculatorTest.java`:
- Around line 33-40: Extract the duplicated spy-and-fixed-date setup into a
private helper method (e.g., createCalculatorWithFixedDate or
setupCalculatorWithDate) that constructs the BaselineStatsCalculator spy, stubs
currentDate() via Mockito.doReturn(fixedDate).when(calculator).currentDate(),
and returns the prepared spy (and any commonly used fixtures like the fixed
LocalDate or User/ActivityStatistics via overloaded helpers if needed); then
replace the repeated blocks that create the BaselineStatsCalculator, call
Mockito.doReturn(...).when(calculator).currentDate(), and set up user(...) and
stats(...) with calls to this helper to remove duplication and clarify intent.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserPersistenceServiceTest.java`:
- Around line 108-113: Add a verification that the repository persist call
happened: in UserPersistenceServiceTest after calling
updateUserStatisticsWithLog(1L, totalStats, baselineStats) and after the
existing verifies for activityLogOrchestrator and rankingRecalculationService,
add a verify on the mocked userRepository that save(...) was called (e.g.,
verify(userRepository).save(...) or verify(userRepository).save(same(user))
using the existing user test fixture) to ensure the persistence path in
updateUserStatisticsWithLog is exercised.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserRefreshServiceTest.java`:
- Around line 92-95: Replace the null-based stubbing with a concrete fixture for
the raw GitHub response: create a mock or fixture object (e.g., rawResponse) and
use it in the when(...) for gitHubActivityService.fetchRawAllActivities("alice",
user.getGithubCreatedAt()) instead of null, then update the dependent stubs to
reference that same rawResponse
(gitHubDataMapper.toActivityStatistics(rawResponse) and
baselineStatsCalculator.calculate(user, rawResponse)) while keeping the final
updateUserStatisticsWithLog(1L, totalStats, baselineStats) stub unchanged; this
ensures the test exercises a realistic non-null contract for
fetchRawAllActivities and remains robust to API changes.

In
`@src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java`:
- Around line 95-100: In UserRegistrationServiceTest, extend the assertions on
the existing "existing user" scenario to cover all relevant response fields so
mapping regressions are caught: after asserting response.username(),
response.isNewUser(), response.email(), and response.profileImage(), also assert
response.userId() and response.commitCount() (and keep response.isNewUser()
assertion) to match the expected values for an existing user; ensure the same
additional assertions are added in the other case mentioned (lines 122-124).
Leave the existing verify(...) checks for
gitHubActivityService.fetchRawAllActivities(...) and
businessMetrics.incrementRegistrations() intact.

In `@src/test/java/com/gitranker/api/support/TestFixtures.java`:
- Around line 47-53: Extract the hardcoded repeated literals used in
TestFixtures (e.g., the LocalDate.of(2025, 1, 1) in emptyActivityLog and
activityLog and any repeated identifier literals referenced around lines 63-71)
into private static final constants at the top of the class (e.g., TEST_DATE and
any repeated IDs/names), then replace the inline calls in ActivityLog.empty,
ActivityLog.of and related helper methods with those constants so all tests
share the same single source of truth.
🪄 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: CHILL

Plan: Pro

Run ID: e4b7e650-6f24-4e4c-a8a5-c6049d9030ed

📥 Commits

Reviewing files that changed from the base of the PR and between 3552ddf and 4d92bbf.

📒 Files selected for processing (26)
  • .github/workflows/ci.yml
  • .github/workflows/deploy.yml
  • AGENTS.md
  • build.gradle
  • src/main/java/com/gitranker/api/domain/badge/BadgeFormatter.java
  • src/main/java/com/gitranker/api/domain/badge/BadgeService.java
  • src/main/java/com/gitranker/api/domain/badge/SvgBadgeRenderer.java
  • src/main/java/com/gitranker/api/domain/user/service/BaselineStatsCalculator.java
  • src/test/java/com/gitranker/api/domain/auth/service/AuthServiceTest.java
  • src/test/java/com/gitranker/api/domain/auth/service/RefreshTokenServiceTest.java
  • src/test/java/com/gitranker/api/domain/badge/BadgeFormatterTest.java
  • src/test/java/com/gitranker/api/domain/badge/BadgeServiceTest.java
  • src/test/java/com/gitranker/api/domain/badge/SvgBadgeRendererTest.java
  • src/test/java/com/gitranker/api/domain/badge/TierGradientProviderTest.java
  • src/test/java/com/gitranker/api/domain/failure/BatchFailureLogServiceTest.java
  • src/test/java/com/gitranker/api/domain/log/ActivityLogServiceTest.java
  • src/test/java/com/gitranker/api/domain/ranking/RankingRecalculationServiceTest.java
  • src/test/java/com/gitranker/api/domain/ranking/RankingServiceTest.java
  • src/test/java/com/gitranker/api/domain/user/service/BaselineStatsCalculatorTest.java
  • src/test/java/com/gitranker/api/domain/user/service/UserDeletionServiceTest.java
  • src/test/java/com/gitranker/api/domain/user/service/UserPersistenceServiceTest.java
  • src/test/java/com/gitranker/api/domain/user/service/UserQueryServiceTest.java
  • src/test/java/com/gitranker/api/domain/user/service/UserRefreshServiceTest.java
  • src/test/java/com/gitranker/api/domain/user/service/UserRegistrationServiceTest.java
  • src/test/java/com/gitranker/api/global/util/TimeUtilsTest.java
  • src/test/java/com/gitranker/api/support/TestFixtures.java

Comment thread src/test/java/com/gitranker/api/domain/auth/service/AuthServiceTest.java Outdated
- unresolved PR 리뷰 스레드의 테스트 안정성 피드백 반영
- TestFixtures 의존을 단순화해 IDE 해석 안정성 개선
- badge diff 포맷과 응답 단언 범위를 보강
@alexization alexization merged commit fc85948 into develop Apr 14, 2026
2 checks passed
@alexization alexization deleted the test/86-backend-unit-test-baseline branch April 14, 2026 06:57
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