# Flutter 테스트 자동화 가이드 ## 📋 개요 이 문서는 Flutter 앱의 테스트 자동화를 위한 가이드입니다. 각 화면의 버튼 클릭, 서버 통신, 데이터 입력/수정/저장 등 모든 액션에 대한 테스트를 포함합니다. ## 🏗️ 테스트 구조 ``` test/ ├── helpers/ # 테스트 헬퍼 클래스 │ ├── test_helpers.dart # 기본 테스트 헬퍼 │ ├── mock_data_helpers.dart # Mock 데이터 생성 헬퍼 │ └── simple_mock_services.dart # Mock 서비스 설정 ├── unit/ # 단위 테스트 │ └── controllers/ # 컨트롤러 테스트 ├── widget/ # Widget 테스트 │ └── screens/ # 화면별 Widget 테스트 └── integration/ # 통합 테스트 ``` ## 🔧 테스트 환경 설정 ### 1. 필요한 패키지 (pubspec.yaml) ```yaml dev_dependencies: flutter_test: sdk: flutter integration_test: sdk: flutter mockito: ^5.4.5 build_runner: ^2.4.9 golden_toolkit: ^0.15.0 mocktail: ^1.0.3 fake_async: ^1.3.1 test: ^1.25.2 coverage: ^1.7.2 patrol: ^3.6.0 ``` ### 2. Mock 클래스 생성 ```bash flutter pub run build_runner build --delete-conflicting-outputs ``` ## 📝 테스트 작성 예제 ### 1. 컨트롤러 단위 테스트 ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:get_it/get_it.dart'; import 'package:mockito/mockito.dart'; void main() { late CompanyListController controller; late MockMockDataService mockDataService; late MockCompanyService mockCompanyService; late GetIt getIt; setUp(() { getIt = setupTestGetIt(); mockDataService = MockMockDataService(); mockCompanyService = MockCompanyService(); // GetIt에 서비스 등록 getIt.registerSingleton(mockCompanyService); // Mock 설정 SimpleMockServiceHelpers.setupMockDataServiceMock(mockDataService); SimpleMockServiceHelpers.setupCompanyServiceMock(mockCompanyService); controller = CompanyListController(dataService: mockDataService); }); tearDown(() { controller.dispose(); getIt.reset(); }); group('CompanyListController 테스트', () { test('검색 기능 테스트', () async { await controller.updateSearchKeyword('테스트'); expect(controller.searchKeyword, '테스트'); }); }); } ``` ### 2. Widget 테스트 ```dart testWidgets('화면 렌더링 테스트', (WidgetTester tester) async { await pumpTestWidget( tester, const CompanyListRedesign(), ); await pumpAndSettleWithTimeout(tester); expect(find.text('회사 관리'), findsOneWidget); expect(find.byType(TextField), findsOneWidget); }); ``` ### 3. Mock 데이터 생성 ```dart // 회사 목록 생성 final companies = MockDataHelpers.createMockCompanyList(count: 5); // 특정 회사 생성 final company = MockDataHelpers.createMockCompany( id: 1, name: '테스트 회사', ); ``` ## 🎯 테스트 전략 ### 1. 단위 테스트 (Unit Tests) - **대상**: 컨트롤러, 서비스, 유틸리티 함수 - **목적**: 개별 컴포넌트의 로직 검증 - **실행**: `flutter test test/unit/` ### 2. Widget 테스트 - **대상**: 개별 화면 및 위젯 - **목적**: UI 렌더링 및 상호작용 검증 - **실행**: `flutter test test/widget/` ### 3. 통합 테스트 (Integration Tests) - **대상**: 전체 사용자 플로우 - **목적**: 실제 앱 동작 검증 - **실행**: `flutter test integration_test/` ## 🔍 주요 테스트 케이스 ### 화면별 필수 테스트 1. **초기 렌더링**: 화면이 올바르게 표시되는지 확인 2. **데이터 로딩**: API 호출 및 데이터 표시 확인 3. **사용자 입력**: 텍스트 입력, 버튼 클릭 등 4. **네비게이션**: 화면 전환 동작 확인 5. **에러 처리**: 네트워크 오류, 유효성 검사 실패 등 6. **상태 관리**: 로딩, 성공, 실패 상태 전환 ## 🚨 주의사항 ### 1. 모델 불일치 문제 - 실제 모델과 Mock 모델의 구조가 일치하는지 확인 - 특히 `Address`, `Company`, `User` 모델 주의 ### 2. 서비스 시그니처 - Mock 서비스의 메서드 시그니처가 실제 서비스와 일치해야 함 - 반환 타입 특히 주의 (예: `User` vs `AuthUser`) ### 3. GetIt 설정 - 테스트 전 반드시 GetIt 초기화 - 테스트 후 반드시 GetIt reset ## 📊 테스트 커버리지 ### 커버리지 확인 ```bash flutter test --coverage genhtml coverage/lcov.info -o coverage/html open coverage/html/index.html ``` ### 목표 커버리지 - 단위 테스트: 80% 이상 - Widget 테스트: 70% 이상 - 통합 테스트: 주요 사용자 시나리오 100% ## 🔄 CI/CD 통합 ### GitHub Actions 예제 ```yaml name: Test on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: subosito/flutter-action@v2 - run: flutter pub get - run: flutter test - run: flutter test --coverage ``` ## 📚 추가 리소스 - [Flutter Testing Documentation](https://flutter.dev/docs/testing) - [Mockito Documentation](https://pub.dev/packages/mockito) - [GetIt Documentation](https://pub.dev/packages/get_it) ## 🔧 문제 해결 ### Mock 클래스를 찾을 수 없을 때 ```bash flutter pub run build_runner build --delete-conflicting-outputs ``` ### 테스트가 타임아웃될 때 `pumpAndSettleWithTimeout` 헬퍼 사용: ```dart await pumpAndSettleWithTimeout(tester, timeout: Duration(seconds: 10)); ``` ### GetIt 관련 오류 ```dart setUp(() { getIt = setupTestGetIt(); // 반드시 첫 번째로 실행 }); tearDown(() { getIt.reset(); // 반드시 실행 }); ```