272 lines
7.9 KiB
Markdown
272 lines
7.9 KiB
Markdown
# 테스트 문제 해결 가이드
|
|
|
|
## 목차
|
|
1. [소개](#소개)
|
|
2. [일반적인 테스트 실패 원인](#일반적인-테스트-실패-원인)
|
|
3. [EventBus 관련 문제](#eventbus-관련-문제)
|
|
4. [비동기 테스트 문제](#비동기-테스트-문제)
|
|
5. [메모리 및 리소스 관리 문제](#메모리-및-리소스-관리-문제)
|
|
6. [CI 환경 특화 문제](#ci-환경-특화-문제)
|
|
7. [문제 해결 도구](#문제-해결-도구)
|
|
8. [테스트 실행 가이드](#테스트-실행-가이드)
|
|
|
|
## 소개
|
|
|
|
이 문서는 볼링 매니저 앱의 테스트 실행 중 발생할 수 있는 다양한 문제와 그 해결 방법을 설명합니다. 특히 EventBus와 MemberService 테스트의 신뢰성 문제에 초점을 맞추고 있습니다.
|
|
|
|
## 일반적인 테스트 실패 원인
|
|
|
|
### 1. 테스트 간 상태 격리 실패
|
|
|
|
**증상:**
|
|
- 테스트를 개별적으로 실행하면 통과하지만, 전체 테스트를 실행하면 실패
|
|
- 테스트 실행 순서에 따라 결과가 달라짐
|
|
|
|
**원인:**
|
|
- 테스트 간 공유 상태(싱글톤, 정적 변수 등)가 적절히 초기화되지 않음
|
|
- 테스트 종료 후 리소스가 제대로 정리되지 않음
|
|
|
|
**해결 방법:**
|
|
- `setUp`과 `tearDown`에서 모든 공유 상태 초기화
|
|
- 싱글톤 인스턴스를 테스트마다 재설정
|
|
- `TestUtils.isInTest` 플래그를 활용하여 테스트 환경에서 특별한 처리 적용
|
|
- 격리 모드를 `strict`로 설정하여 테스트 간 상태 공유 최소화
|
|
|
|
### 2. 타이밍 및 비동기 문제
|
|
|
|
**증상:**
|
|
- 간헐적인 테스트 실패
|
|
- `Timeout` 오류 발생
|
|
- 비동기 작업 완료 전에 테스트가 종료됨
|
|
|
|
**원인:**
|
|
- 고정된 지연 시간(`Future.delayed`)에 의존
|
|
- 비동기 작업 완료를 적절히 기다리지 않음
|
|
- 테스트 환경(CI vs 로컬)에 따른 실행 속도 차이
|
|
|
|
**해결 방법:**
|
|
- 고정 지연 대신 `TestConfig`에서 환경별 설정 사용
|
|
- `expectLater`와 `completes` 매처 활용
|
|
- 비동기 작업 완료를 명시적으로 기다리는 코드 추가
|
|
|
|
## EventBus 관련 문제
|
|
|
|
### 1. 구독 해제 문제
|
|
|
|
**증상:**
|
|
- `EventBus: 구독 취소됨` 로그가 누락됨
|
|
- 활성 구독 수(`_activeSubscriptionCount`)가 감소하지 않음
|
|
- 테스트 간 이벤트 간섭 발생
|
|
|
|
**원인:**
|
|
- `dispose()` 메서드에서 구독 취소가 제대로 이루어지지 않음
|
|
- 구독 취소 전에 테스트가 종료됨
|
|
- 구독 카운터 관리 버그
|
|
|
|
**해결 방법:**
|
|
- `dispose()` 메서드에서 모든 구독을 명시적으로 취소
|
|
- `tearDown`에서 `EventBus.resetAllTestInstances()` 호출
|
|
- 테스트 ID를 사용하여 테스트별 EventBus 인스턴스 격리
|
|
|
|
### 2. 이벤트 전달 문제
|
|
|
|
**증상:**
|
|
- 이벤트가 발생했지만 구독자에게 전달되지 않음
|
|
- 테스트에서 이벤트 처리 검증 실패
|
|
|
|
**원인:**
|
|
- 이벤트 발생과 처리 사이의 비동기 타이밍 문제
|
|
- 잘못된 테스트 ID로 인한 이벤트 격리
|
|
- 이벤트 구독 전에 이벤트가 발생함
|
|
|
|
**해결 방법:**
|
|
- 이벤트 발생 후 적절한 지연 추가 (환경 설정 기반)
|
|
- 테스트 ID 설정 확인
|
|
- 이벤트 발생 전에 구독이 완료되었는지 확인
|
|
|
|
## 비동기 테스트 문제
|
|
|
|
### 1. 타임아웃 문제
|
|
|
|
**증상:**
|
|
- `Test timed out after X milliseconds` 오류
|
|
- CI 환경에서 더 자주 발생
|
|
|
|
**원인:**
|
|
- 테스트 타임아웃 값이 너무 짧음
|
|
- 비동기 작업이 예상보다 오래 걸림
|
|
- 리소스 경합으로 인한 지연
|
|
|
|
**해결 방법:**
|
|
- `TestConfig`를 통해 환경별 타임아웃 값 조정
|
|
- 비동기 작업 완료를 명시적으로 기다림
|
|
- CI 환경에서 더 긴 타임아웃 설정
|
|
|
|
### 2. 비동기 작업 완료 대기 문제
|
|
|
|
**증상:**
|
|
- 비동기 작업 결과를 검증하기 전에 테스트가 종료됨
|
|
- 간헐적인 테스트 실패
|
|
|
|
**원인:**
|
|
- `await`가 누락됨
|
|
- 잘못된 비동기 패턴 사용
|
|
- 이벤트 루프 블로킹
|
|
|
|
**해결 방법:**
|
|
- 모든 비동기 작업에 `await` 사용
|
|
- `expectLater`와 함께 `completes` 또는 `completion` 매처 사용
|
|
- `pumpAndSettle`을 사용하여 모든 마이크로태스크가 완료될 때까지 대기
|
|
|
|
## 메모리 및 리소스 관리 문제
|
|
|
|
### 1. 리소스 누수
|
|
|
|
**증상:**
|
|
- 메모리 사용량 증가
|
|
- 테스트 실행이 느려짐
|
|
- 장시간 테스트 실행 시 실패 증가
|
|
|
|
**원인:**
|
|
- `dispose()` 메서드에서 리소스 정리 누락
|
|
- 구독, 스트림, 컨트롤러 등이 제대로 닫히지 않음
|
|
- 테스트 간 공유 리소스가 정리되지 않음
|
|
|
|
**해결 방법:**
|
|
- 모든 서비스 클래스에 철저한 `dispose()` 구현
|
|
- `tearDown`에서 모든 리소스 정리
|
|
- 메모리 누수 감지 도구 활용
|
|
|
|
### 2. 구독 관리 문제
|
|
|
|
**증상:**
|
|
- `EventBus` 활성 구독 수가 계속 증가
|
|
- 이벤트가 예상보다 많은 구독자에게 전달됨
|
|
|
|
**원인:**
|
|
- 구독 취소가 제대로 이루어지지 않음
|
|
- 구독 카운터 관리 버그
|
|
- 테스트 간 구독 객체 공유
|
|
|
|
**해결 방법:**
|
|
- 모든 구독을 변수에 저장하고 명시적으로 취소
|
|
- `StreamSubscription` 객체 관리 개선
|
|
- 테스트 ID 기반 구독 격리
|
|
|
|
## CI 환경 특화 문제
|
|
|
|
### 1. 환경 차이로 인한 문제
|
|
|
|
**증상:**
|
|
- 로컬에서는 통과하지만 CI에서는 실패하는 테스트
|
|
- CI에서 더 느린 테스트 실행 속도
|
|
- 리소스 제약으로 인한 타임아웃
|
|
|
|
**원인:**
|
|
- CI 환경의 제한된 리소스 (CPU, 메모리)
|
|
- 환경별 설정 차이
|
|
- 병렬 실행으로 인한 리소스 경합
|
|
|
|
**해결 방법:**
|
|
- 환경 감지 및 설정 자동 조정 (`TestConfig` 활용)
|
|
- CI 환경에서 더 긴 타임아웃 및 지연 설정
|
|
- 필요시 CI에서 순차 실행 적용
|
|
|
|
### 2. 로깅 및 디버깅 문제
|
|
|
|
**증상:**
|
|
- CI에서 테스트 실패 원인 파악이 어려움
|
|
- 로그 정보 부족
|
|
|
|
**원인:**
|
|
- CI 환경에서 제한된 로그 출력
|
|
- 디버깅 정보 부족
|
|
|
|
**해결 방법:**
|
|
- CI 환경에서 상세 로깅 활성화
|
|
- `TestDiagnostics` 유틸리티를 통한 자동 진단 정보 수집
|
|
- 실패 시 시스템 정보 수집 및 저장
|
|
|
|
## 문제 해결 도구
|
|
|
|
### 1. 테스트 진단 유틸리티
|
|
|
|
`TestDiagnostics` 클래스는 테스트 실패 시 자동으로 진단 정보를 수집하고 분석합니다:
|
|
|
|
```dart
|
|
// 테스트 실패 기록
|
|
TestDiagnostics.instance.recordFailure(
|
|
'테스트 이름',
|
|
'오류 메시지',
|
|
stackTrace: stackTrace
|
|
);
|
|
|
|
// 테스트 종료 시 요약 생성
|
|
await TestDiagnostics.instance.generateSummary();
|
|
```
|
|
|
|
### 2. 테스트 재현 스크립트
|
|
|
|
테스트 실패를 재현하고 진단하기 위한 스크립트:
|
|
|
|
```bash
|
|
# 특정 테스트 재현
|
|
./scripts/reproduce_test.sh "MemberService 테스트" --verbose
|
|
|
|
# 환경별 테스트 실행
|
|
./scripts/run_tests.sh ci --pattern="EventBus" --timeout=3000
|
|
```
|
|
|
|
### 3. 테스트 설정 관리
|
|
|
|
환경별 테스트 설정을 관리하기 위한 `TestConfig` 클래스:
|
|
|
|
```dart
|
|
// 환경별 설정 사용
|
|
final timeout = TestConfig.instance.asyncTimeout;
|
|
final delay = TestConfig.instance.testDelayDuration;
|
|
|
|
// 비동기 작업 대기
|
|
await Future.delayed(delay);
|
|
```
|
|
|
|
## 테스트 실행 가이드
|
|
|
|
### 로컬 환경에서 테스트 실행
|
|
|
|
```bash
|
|
# 전체 테스트 실행
|
|
./scripts/run_tests.sh local
|
|
|
|
# 특정 테스트만 실행
|
|
./scripts/run_tests.sh local --pattern="MemberService"
|
|
|
|
# 상세 로그와 함께 실행
|
|
./scripts/run_tests.sh local --verbose
|
|
```
|
|
|
|
### CI 환경에서 테스트 실행
|
|
|
|
```bash
|
|
# CI 환경 설정으로 테스트 실행
|
|
./scripts/run_tests.sh ci
|
|
|
|
# 순차 실행 (병렬 실행 비활성화)
|
|
./scripts/run_tests.sh ci --sequential
|
|
|
|
# 타임아웃 증가
|
|
./scripts/run_tests.sh ci --timeout=5000
|
|
```
|
|
|
|
### 테스트 실패 분석
|
|
|
|
```bash
|
|
# 실패한 테스트 재현
|
|
./scripts/reproduce_test.sh "실패한 테스트 이름"
|
|
|
|
# 진단 정보 수집
|
|
./scripts/reproduce_test.sh "실패한 테스트 이름" --verbose
|
|
```
|
|
|
|
테스트 진단 로그는 `test_diagnostics` 디렉토리에 저장되며, 실패 분석 및 재현 스크립트도 이 디렉토리에 생성됩니다.
|