Skip to content

refactor: 테스트 구조 개선 및 신규 케이스 추가#81

Merged
gagip merged 12 commits intomainfrom
refactor/test
Mar 27, 2026
Merged

refactor: 테스트 구조 개선 및 신규 케이스 추가#81
gagip merged 12 commits intomainfrom
refactor/test

Conversation

@gagip
Copy link
Copy Markdown
Owner

@gagip gagip commented Mar 27, 2026

Summary

  • 테스트 코드의 구조를 coroutineTestScope 패턴과 Turbine awaitItem 명시 패턴으로 통일하고, 공통 픽스처(TrackFixtures)를 분리하여 재사용성을 높임
  • PomodoroManager, ZenViewModel, PlayQueueManager, PlaylistDetailViewModel 등 주요 컴포넌트에 누락된 시나리오 케이스를 보완

Key Changes

  • TrackFixtures.kt 공통 픽스처 파일 신규 추출 — 여러 테스트에서 makeTrack() 재사용
  • ZenMusicSelectViewModelTest: Retry while 루프 → Turbine awaitItem 명시 패턴으로 교체
  • PomodoroManager, TimerEngine, FallbackAwareMusicRepository: coroutineTestScope 패턴으로 통일
  • PomodoroManagerTest: RUNNING 상태에서 설정 변경 시 상태 유지 케이스 추가
  • ZenViewModelTest: skip 액션 시나리오 추가
  • PlayQueueManagerTest: 셔플 테스트를 행동 기반 검증으로 교체, 셔플 OFF 복귀 케이스 추가
  • PlaylistDetailViewModelTest: 트랙 제거 성공 후 목록 갱신 케이스 추가
  • docs/testing.md: 내용 불일치 및 중복 정리

Technical Details

  • coroutineTestScope 패턴: TestScope + UnconfinedTestDispatcher를 공통 헬퍼로 감싸 보일러플레이트 제거
  • Turbine awaitItem 패턴: while 루프 기반의 비결정적 대기를 제거하고 명시적 아이템 소비로 교체
  • TimerTestUtils.kt 헬퍼 신규 추가로 타이머 관련 테스트 공통 로직 집중
  • FakeZenPlayerBinder 소폭 조정으로 신규 시나리오 테스트 지원

Rationale

  • while 루프 기반 polling은 타이밍에 민감하고 flaky test를 유발할 수 있어 Turbine의 구조적 대기 방식으로 대체
  • 공통 픽스처 분리로 테스트 간 데이터 불일치를 방지하고 유지보수 비용 절감
  • coroutineTestScope 패턴 통일로 TestCoroutineDispatcher 누수 경고 제거

gagip added 9 commits March 27, 2026 12:30
- BehaviorSpec 예시에서 runTest 제거, coroutineTestScope 패턴으로 통일
- Given/When/Then 코드 배치 규칙을 테스트 작성 규칙 섹션으로 통합
- 도메인/ViewModel 계층별 중복 배치 규칙 제거, 특이사항만 잔류
- 코루틴 테스트 항목 신설 (coroutineTestScope, backgroundScope 규칙)
- private 검증 금지 항목을 테스트 기준점에 추가
- Mockk 사용 기준에 인터페이스 추상화 대안 명시
- 예시 코드를 실전 클래스 대신 가상 예제(FooTest)로 교체
…allbackAwareMusicRepository)

- runTest {} 래핑 제거, coroutineTestScope = true 선언으로 통일
- scope 주입 클래스는 CoroutineScope(UnconfinedTestDispatcher(testScheduler)) 사용
- 코루틴 시간 조작은 testScheduler.advanceTimeBy() 사용
- TimerTestUtils에 TestScope 없이 사용 가능한 elapse() 오버로드 추가
- Given/When/Then 배치 규칙 준수 (Given: 준비, When: 객체+액션, Then: 검증)
- docs/testing.md 코루틴 테스트 섹션을 실제 Kotest 동작에 맞게 수정
- seed 기반 인덱스 하드코딩 → 5곡 모두 한 번씩 방문하는 행동 기반 검증으로 교체
- 셔플 ON 상태에서 OFF로 토글 시 currentIndex가 원래 인덱스를 유지하는 케이스 추가
…시 패턴으로 교체

- StateFlow conflation으로 Loading이 합쳐져 Success 상태 하나만 방출됨을 확인
- while 루프 + 재시도 카운터 → awaitItem() 단일 호출로 단순화
- 불필요해진 fail import 제거
- core/model/TrackFixtures.kt 신규 생성 (testTrack 함수)
- PlayQueueManagerTest, PlaylistDetailViewModelTest, ZenMusicSelectViewModelTest,
  MiniPlayerViewModelTest, FallbackAwareMusicRepositoryTest 5개 파일 로컬 makeTrack 제거 후 testTrack으로 치환
- 호출 시 named argument 사용 강제
- FOCUS RUNNING 상태에서 PomodoroSkip 시 세션이 BREAK로 전환되고 RUNNING 유지 검증
- FakeZenPlayerBinder.skipPomodoro()에 실제 세션 전환 로직 추가
- focusDuration 설정 변경 시 현재 세션의 timerState(RUNNING)가 유지되는지 검증
- Dispatchers.setMain()을 각 Given에서 beforeTest로 통합 (4개 파일)
- PlayQueueManager 셔플 OFF 토글 테스트에 고정 seed(42) 적용으로 결정론적 검증 보장
- PomodoroManagerTest elapse() 행동 코드를 Then → When 블록으로 이동 (4곳)
- FallbackAwareMusicRepositoryTest Then 블록을 반환값/isFallback 검증으로 분리
- MiniPlayerViewModelTest fakeTrack을 사용하는 Given 블록 내부로 스코프 이동
- PlayQueueManagerTest makeManager() 생성을 Then → When 블록으로 이동
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

Coverage Report

Module Coverage Covered Total
Total 19.54% 917 4692
Player 36.30% 102 281
Playlist 19.59% 77 393
Timer 48.94% 371 758
Music 21.08% 39 185

@gagip gagip marked this pull request as ready for review March 27, 2026 06:02
@gagip gagip requested a review from Copilot March 27, 2026 06:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

테스트 코드 전반의 패턴을 coroutineTestScope 기반으로 통일하고, Turbine 소비 방식/공통 픽스처 분리를 통해 flaky 가능성을 낮추며 주요 컴포넌트의 누락 시나리오를 보강하는 PR입니다.

Changes:

  • 테스트 전역에서 Dispatchers.setMain/resetMain, coroutineTestScope = true 사용 패턴을 정리하고 Turbine 소비 로직을 명시화
  • testTrack() 공통 픽스처 및 타이머 테스트 유틸(elapse overload) 추가로 중복 제거
  • Pomodoro/Zen/PlayQueue/PlaylistDetail 등에서 신규 시나리오 테스트 케이스 추가 및 FakeBinder 동작 보강

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
docs/testing.md 코루틴 테스트/코드 배치 규칙 및 Fake/Mockk 가이드 정리
app/src/test/java/com/happyseal/zenplayer/core/model/TrackFixtures.kt 테스트용 testTrack() 공통 픽스처 추가
app/src/test/java/com/happyseal/zenplayer/zen/musicselect/ZenMusicSelectViewModelTest.kt testTrack() 적용 및 Retry 케이스의 Turbine 소비 방식 변경
app/src/test/java/com/happyseal/zenplayer/zen/ZenViewModelTest.kt Dispatchers.setMain 설정 방식 정리 + Pomodoro skip 시나리오 추가
app/src/test/java/com/happyseal/zenplayer/zen/MiniPlayerViewModelTest.kt testTrack() 적용 및 setMain 설정 위치 정리
app/src/test/java/com/happyseal/zenplayer/zen/FakeZenPlayerBinder.kt Pomodoro skip 동작을 상태 전환 가능하게 보강
app/src/test/java/com/happyseal/zenplayer/features/timer/domain/TimerTestUtils.kt TestCoroutineScheduler 기반 elapse() 유틸 추가
app/src/test/java/com/happyseal/zenplayer/features/timer/domain/TimerEngineTest.kt runTest 제거, coroutineTestScope 기반으로 타이머 테스트 구조 변경
app/src/test/java/com/happyseal/zenplayer/features/timer/domain/PomodoroManagerTest.kt runTest 제거, coroutineTestScope 기반으로 구조 변경 + 신규 케이스 추가
app/src/test/java/com/happyseal/zenplayer/features/playlist/ui/PlaylistDetailViewModelTest.kt testTrack() 적용 + 트랙 제거 후 목록 갱신 케이스 추가
app/src/test/java/com/happyseal/zenplayer/features/player/data/PlayQueueManagerTest.kt 셔플 테스트를 행동 기반 검증으로 변경 및 OFF 복귀 케이스 추가
app/src/test/java/com/happyseal/zenplayer/features/music/data/FallbackAwareMusicRepositoryTest.kt runTest 제거, coroutineTestScope 기반으로 구조 정리

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

gagip added 3 commits March 27, 2026 16:08
- PomodoroManagerTest: scope를 변수로 추출하고 Then 블록 마지막에 dispose()/cancel() 추가
- ZenMusicSelectViewModelTest: Retry 후 Loading 상태 방출 시 건너뛰도록 flaky 테스트 수정
- scope를 변수로 추출하고 Then 블록 마지막에 dispose()/cancel() 추가
- dispose()/scope.cancel() 호출 필요성 및 예시 코드 추가
- TestCoroutineScheduler 공유 시 주의사항 추가
@gagip gagip merged commit 1195746 into main Mar 27, 2026
1 check passed
@gagip gagip deleted the refactor/test branch March 27, 2026 08:00
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