Skip to content

StorageScrapFragment Compose 마이그레이션 및 ViewModel/UI 테스트 추가#399

Merged
unam98 merged 1 commit into
developfrom
test/add-viewmodel-unit-test-infra
Jun 26, 2026
Merged

StorageScrapFragment Compose 마이그레이션 및 ViewModel/UI 테스트 추가#399
unam98 merged 1 commit into
developfrom
test/add-viewmodel-unit-test-infra

Conversation

@unam98

@unam98 unam98 commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

작업 배경

  • Runnect-Android Compose+TDD 전환 전략의 일환 — Storage 패키지를 첫 번째 적용 대상으로 선택
  • AI 기반 개발/유지보수 시 회귀를 자동으로 잡을 안전망 구축이 목적

변경 사항

영역 내용
StorageScrapFragment XML+RecyclerView+DataBinding → ComposeView 호스팅으로 교체
StorageScrapScreen (신규) LazyVerticalGrid 기반 Compose 화면, 빈 화면/pull-to-refresh 포함
StorageViewModel 테스트 unit test 10개 추가 (성공/실패/선택삭제 토글)
StorageScrapUiStateTest 순수 함수 StorageScrapUiState.from() 단위 테스트 4개
StorageScrapScreenTest Compose UI test 4개 (콜백, 빈 화면 조건, 로딩 인디케이터)
CI testDebugUnitTest/connectedDebugAndroidTest 자동 실행 잡 추가, 실패 시에만 PR 코멘트 게시
삭제 StorageScrapAdapter, OnHeartButtonClick, OnScrapItemClick, XML 레이아웃 2개 제거

영향 범위

  • StorageScrapFragment(보관함 > 스크랩 코스 탭)에 한정
  • 런타임 영향: 없음 (1:1 동작 포팅 + 회귀 3건 수정)

Test Plan

  • StorageViewModel unit test 10개 통과
  • StorageScrapUiState unit test 4개 통과
  • StorageScrapScreen Compose UI test 4개 통과
  • before/after 동작 영상 비교 완료

🤖 Generated with Claude Code

* feat: StorageScrapFragment Compose 마이그레이션 및 ViewModel 테스트 추가

XML/RecyclerView+DataBinding 기반 StorageScrapFragment를 Jetpack Compose로
포팅. 동작은 그대로 유지하고 구현 방식만 교체. StorageViewModel unit test
10개(MockK+Turbine+coroutines-test)도 함께 추가해 회귀 안전망을 마련.

* ci: PR CI에 unit test 실행 단계 추가 및 트리거 확대

기존엔 assembleDebug만 돌고 테스트 검증 없이 빌드 체크만 했음. testDebugUnitTest
스텝을 추가해 모든 PR에서 테스트 결과가 GitHub Actions 체크로 객관적으로 남도록
하고, 트리거도 develop 베이스가 아닌 PR에도 적용되도록 확대.

* fix: CI JDK 버전을 21로 맞춤 (gradle-daemon-jvm.properties와 일치)

gradle/gradle-daemon-jvm.properties는 JetBrains JDK 21을 요구하는데 CI는
Temurin 17로 고정돼 있어 불일치. 이 차이가 원인으로 보이는 kapt+DataBinding
NullPointerException(ProcessDataBinding.getSupportedOptions, processingEnv
null)이 CI에서만 재현됐음. JDK 버전을 21로 맞춰 검증.

* fix: CodeRabbit이 발견한 Compose 포팅 회귀 2건 수정

- 빈 화면이 초기 로딩 중에도 잠깐 보이던 문제: 원본 XML은 로딩 중 그리드/빈화면
  둘 다 숨겼는데 Compose 버전은 courses 기본값이 빈 리스트라 로딩 중에도
  EmptyScrapView가 떴음. isLoading 조건 추가로 수정.
- 동일한 에러가 연속으로 발생하면 두 번째 스낵바가 안 뜨던 문제: LiveData는
  같은 값이어도 항상 옵저버를 호출하지만 Compose State는 동일 키면
  LaunchedEffect가 재실행되지 않아서 생긴 차이. 에러를 보여준 뒤 즉시
  errorMessage를 null로 리셋해서 1회성 이벤트로 만듦.

* test: StorageScrapScreen Compose UI test 3건 추가

검증 매트릭스의 ⚠️ 미검증 항목(카드탭 이동, 빈 화면 진입) 두 곳을 ComposeTestRule로
채움. 빈 화면 테스트는 오늘 고친 로딩 중 깜빡임 회귀를 그대로 락인.

* ci: Compose UI test(androidTest)를 에뮬레이터로 자동 실행하는 잡 추가

connectedDebugAndroidTest는 기기/에뮬레이터가 필요해 기존 unit test 스텝으로
커버되지 않았음. reactivecircus/android-emulator-runner로 PR마다 자동
실행되도록 별도 잡(android-test)을 추가하고, 결과 XML을 아티팩트로 업로드.
REMOTE_KEY_FORCE_UPDATE secret 누락 이슈가 풀려야 함께 정상 동작함.

* fix: 스크랩 해제(하트탭) 시 누락된 로딩 피드백 복구

원본은 courseScrapState Loading 상태에서 프로그레스바를 띄웠지만 Compose
포팅 시 PullToRefreshBox의 isRefreshing이 myScrapCourseGetState에만
연결돼 하트탭 네트워크 대기 중 아무 피드백 없이 멈춰있다가 아이템이
사라지는 회귀가 있었음. before/after 영상 재검토로 발견.

* refactor: 로딩 상태 결합 로직을 순수 함수로 분리 + 회귀 방지 테스트 추가

StorageScrapUiState.from()으로 getState/scrapState의 Loading 결합 판단을
Fragment 밖으로 빼서 에뮬레이터 없이 JVM 유닛 테스트로 고정.
StorageScrapScreen에는 isLoading=true일 때 로딩 인디케이터가 실제로
보이는지 검증하는 Compose UI test 추가 (네트워크 타이밍에 의존하지 않음).

* fix: CI 에뮬레이터 잡을 macos-latest(Apple Silicon)에 맞춰 arm64-v8a로 수정

x86_64 시스템 이미지는 aarch64 호스트의 QEMU2에서 못 돌아서 에뮬레이터가
즉시 죽고 10분간 부팅 대기만 하다 타임아웃났음. CI 동작 자체가 아니라
잡 설정 문제였음.

* fix: 안드로이드 에뮬레이터 CI 잡을 ubuntu-latest+KVM으로 전환

macOS 러너는 HVF가 HV_UNSUPPORTED를 내면서 하드웨어 가속 자체가 막혀
에뮬레이터가 못 떴음. android-emulator-runner 공식 문서가 권장하는
ubuntu-latest + KVM 활성화 방식으로 변경.

* fix: ExampleInstrumentedTest의 하드코딩된 패키지명 오타 수정

com.example.runnect로 박혀있던 안드로이드 스튜디오 생성 샘플 테스트.
connectedDebugAndroidTest가 CI에서 처음 실제로 도니까 드러난 기존 버그.

* ci: 테스트별 성공/실패를 PR 체크에서 바로 확인하도록 test-reporter 추가

testLogging으로 유닛 테스트가 콘솔에 테스트명 단위 PASSED/FAILED를
찍게 하고, dorny/test-reporter로 유닛/Compose UI 테스트 결과를 각각
별도 체크(Unit Test Results / Compose UI Test Results)로 게시해서
어떤 테스트가 깨졌는지 PR에서 클릭 한 번으로 특정 가능하게 함.

* fix: test-reporter 체크런 생성에 필요한 actions:read 권한 추가

dorny/test-reporter가 테스트 결과 요약은 만들었지만 체크런 생성 API
호출 직전에 조용히 멈췄음. actions:read 권한 누락이 원인.

* fix: dorny/test-reporter를 v3로 올려 체크런 대신 잡 서머리에만 찍히던 문제 해결

v1은 Job Summary로만 동작해서 PR 체크 목록에 안 보였음. 공식 문서가
권장하는 v3로 올려서 실제 체크런으로 생성되게 함.

* ci: dorny/test-reporter 대신 자체 스크립트로 테스트 결과를 PR 코멘트에 게시

dorny/test-reporter(v1/v3 둘 다)는 job summary는 만들지만 체크런 생성은
조용히 안 됐음(에러 없이 스킵, 원인 특정 못함). 더 기본적이고 통제 가능한
방식으로 전환: JUnit XML을 직접 파싱(.github/scripts/post_test_report.py)
해서 테스트별 ✅/❌ 마크다운을 PR 코멘트로 직접 게시(마커 기반으로 같은
코멘트를 갱신, 스팸 방지).

* fix: 테스트 결과 코멘트에서 testcase의 classname으로 그루핑하도록 수정

connectedAndroidTest는 디바이스 1대당 XML 1개에 모든 클래스의 테스트를
합쳐서 쓰는데, testsuite 레벨 name은 첫 번째 클래스명만 가져서 나머지
클래스 테스트가 잘못 묶였음.

* feat: 테스트 결과 코멘트의 각 테스트에 고정 앵커 추가

PR 본문 검증 매트릭스에서 특정 테스트의 최신 통과 여부로 바로 링크
걸 수 있게, classname+테스트명 해시로 만든 안정적인 anchor id를
각 줄에 부여.

* ci: 테스트 실패 시에만 PR 코멘트 게시, 통과 시 코멘트 삭제

- 실패한 테스트만 출력하도록 post_test_report.py 단순화
- 전부 통과하면 기존 실패 코멘트를 삭제, 코멘트 없으면 무시
- 통과/실패 여부는 CI 체크 뱃지로 확인 가능하므로 성공 코멘트 불필요

---------

Co-authored-by: unam98 <unam98@users.noreply.github.com>
@unam98 unam98 merged commit 8a0da8d into develop Jun 26, 2026
3 checks passed
@unam98 unam98 deleted the test/add-viewmodel-unit-test-infra branch June 26, 2026 13:23
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@unam98, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 6 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0609422-b37d-4c64-9826-fb363ba80043

📥 Commits

Reviewing files that changed from the base of the PR and between 3abad2d and 792d7cb.

📒 Files selected for processing (16)
  • .github/scripts/post_test_report.py
  • .github/workflows/CI.yml
  • app/build.gradle
  • app/src/androidTest/java/com/runnect/runnect/ExampleInstrumentedTest.kt
  • app/src/androidTest/java/com/runnect/runnect/presentation/storage/StorageScrapScreenTest.kt
  • app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapFragment.kt
  • app/src/main/java/com/runnect/runnect/presentation/storage/StorageScrapScreen.kt
  • app/src/main/java/com/runnect/runnect/presentation/storage/adapter/StorageScrapAdapter.kt
  • app/src/main/java/com/runnect/runnect/util/callback/listener/OnHeartButtonClick.kt
  • app/src/main/java/com/runnect/runnect/util/callback/listener/OnScrapItemClick.kt
  • app/src/main/res/layout/fragment_storage_scrap.xml
  • app/src/main/res/layout/item_storage_scrap.xml
  • app/src/main/res/values/strings.xml
  • app/src/test/java/com/runnect/runnect/presentation/storage/StorageScrapUiStateTest.kt
  • app/src/test/java/com/runnect/runnect/presentation/storage/StorageViewModelTest.kt
  • gradle/libs.versions.toml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/add-viewmodel-unit-test-infra

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.

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