108 lines
5.0 KiB
Markdown
108 lines
5.0 KiB
Markdown
# Test Utilities Guide
|
|
|
|
본 문서는 Flutter 위젯/서비스 테스트를 안정적으로 작성하기 위한 공용 유틸 사용 가이드를 제공합니다. 실제 예시는 프로젝트 내 테스트 코드에서 그대로 복사해 사용할 수 있습니다.
|
|
|
|
## 구성 요소
|
|
|
|
- test/utils/mock_services.dart
|
|
- test/utils/stub_event_service.dart
|
|
- test/utils/provider_presets.dart
|
|
- test/utils/widget_test_utils.dart (향후 확장 시)
|
|
- test/utils/event_bus_test_utils.dart
|
|
|
|
## 공통 패턴
|
|
|
|
- __오버레이/네비 의존 제거__: 팝업/스낵바/네비게이션은 테스트에서 `pumpAndSettle`를 가로막는 대표 원인입니다. 가능하면 화면에 `@visibleForTesting` 훅(예: `invokeSaveForTest`, `invokeDuplicateForTest`)을 제공하여 내부 로직을 직접 호출하세요.
|
|
- __pumpAndSettle 지양__: 무한 대기 가능성이 있으므로, `await tester.pump()` + `await tester.pump(const Duration(milliseconds: 50))` 조합을 우선적으로 사용합니다.
|
|
- __ensureVisible__: 탭/토글/입력 전에는 `await tester.ensureVisible(finder)`로 화면 내 가시성을 보장합니다.
|
|
- __Key 부여__: 테스트가 찾는 주요 위젯에는 `ValueKey`를 부여합니다. 예) `ValueKey('access_password_field')`, `ValueKey('event_menu_<id>')`.
|
|
- __SharedPreferences 모킹__: 영속 값(검색어 등)을 사용 시 `SharedPreferences.setMockInitialValues({...})`를 통해 초기 상태를 정의합니다.
|
|
|
|
## Mock/Stub 소개
|
|
|
|
### MockAuthService / MockClubService (`test/utils/mock_services.dart`)
|
|
- __MockAuthService__
|
|
- 고정 토큰과 사용자 정보(`User`)를 제공합니다.
|
|
- `isAuthenticated`, `currentUser`, `token` 등을 간단히 반환합니다.
|
|
- __MockClubService__
|
|
- 단일 `Club`을 보유하고 `currentClub`/`clubs`를 제공합니다.
|
|
- `updateClub()`는 `ownerId` 반영 정도만 최소 구현했습니다.
|
|
|
|
사용 예시:
|
|
```dart
|
|
final auth = MockAuthService(
|
|
user: User(id: 'u1', email: 'u@ex.com', name: 'Tester', role: 'owner'),
|
|
tokenValue: 'token',
|
|
);
|
|
final club = MockClubService(
|
|
club: Club(id: 'club1', name: '클럽', averageCalculationPeriod: '3'),
|
|
);
|
|
```
|
|
|
|
### StubEventService (`test/utils/stub_event_service.dart`)
|
|
- 네트워크 호출을 모두 차단하고 즉시 완료되는 `EventService` 대체 구현입니다.
|
|
- __관찰 필드__
|
|
- `lastCloneCalled`, `lastClonedEventId`, `lastCreatedEventData`
|
|
- __시드 이벤트__
|
|
- `seededEvents`에 `Event` 리스트를 주입해 목록을 렌더링합니다.
|
|
- __안정화 포인트__
|
|
- `createEvent/cloneEvent`는 notifyListeners 후 바로 반환합니다.
|
|
|
|
사용 예시:
|
|
```dart
|
|
final stub = StubEventService();
|
|
await stub.initialize('token');
|
|
stub.setClubId('club1');
|
|
stub.seededEvents = [Event(id: 'e1', clubId: 'club1', title: '타이틀', startDate: DateTime.now(), status: '활성', isActive: true)];
|
|
```
|
|
|
|
### Provider 프리셋 (`test/utils/provider_presets.dart`)
|
|
- 특정 화면에 필요한 Provider 집합을 손쉽게 구성합니다.
|
|
- 현재 예시는 ClubSettings 시나리오용으로 제공되며, 필요 시 확장하세요.
|
|
|
|
사용 예시:
|
|
```dart
|
|
MultiProvider(
|
|
providers: [
|
|
ChangeNotifierProvider<AuthService>.value(value: auth),
|
|
ChangeNotifierProvider<ClubService>.value(value: club),
|
|
ChangeNotifierProvider<EventService>.value(value: stub),
|
|
],
|
|
child: const MaterialApp(home: EventsScreen()),
|
|
);
|
|
```
|
|
|
|
## 화면별 테스트 팁
|
|
|
|
### EventsScreen
|
|
- __복제 메뉴 테스트__: `PopupMenuButton` 오버레이를 열지 말고, 상태 훅 `invokeDuplicateForTest(event)`를 호출하세요.
|
|
- __ellipsis 회귀 테스트__: `Text` 위젯을 `find.textContaining()`으로 찾고, `Text.maxLines`/`Text.overflow`를 직접 검증하세요.
|
|
|
|
### EventFormScreen
|
|
- __저장 테스트__: 저장 버튼 탭 대신 `invokeSaveForTest()` 호출. 테스트 모드에서는 pop/스낵바를 우회하고 `_isLoading`을 해제하는 로직이 포함되어 있어 hang 방지에 유리합니다.
|
|
- __비밀번호 필드__: `ValueKey('access_password_field')`로 필드 접근, 토글 아이콘은 `Tooltip('비밀번호 표시')`/`('비밀번호 숨김')`으로 찾습니다.
|
|
|
|
## EventBus 테스트 유틸 (`test/utils/event_bus_test_utils.dart`)
|
|
- 각 테스트에서 고유 테스트 ID를 설정하고, setUp/tearDown에서 `EventBus`를 초기화/해제합니다.
|
|
- 간헐적 경합을 줄이기 위해 tearDown에서 짧은 대기(`Future.delayed`)를 추가합니다.
|
|
|
|
샘플 패턴:
|
|
```dart
|
|
setUp(() async {
|
|
final testId = 'member_service_test_${DateTime.now().millisecondsSinceEpoch}';
|
|
await EventBusTestUtils.setUp(testId);
|
|
});
|
|
|
|
tearDown(() async {
|
|
await EventBusTestUtils.tearDown();
|
|
await Future<void>.delayed(const Duration(milliseconds: 100));
|
|
});
|
|
```
|
|
|
|
## 권장 사항 요약
|
|
|
|
- __핵심__: 오버레이/네비 의존 제거, 테스트 훅 사용, `pumpAndSettle` 지양.
|
|
- __상태__: `_isLoading`은 성공/실패 모두 해제되도록 보장.
|
|
- __가시성__: 액션 전 `ensureVisible` 사용.
|
|
- __모델/타입__: 실제 모델 시그니처에 맞는 파라미터(문자열/정수, const 사용 여부 등) 확인.
|