Files
superport/TEST_GUIDE.md
JiWoong Sul d6f34c0a52 test: 테스트 자동화 구현 및 Mock 서비스 오류 수정
- 테스트 패키지 추가 (mockito, golden_toolkit, patrol 등)
- 테스트 가이드 문서 작성 (TEST_GUIDE.md)
- 테스트 진행 상황 문서 작성 (TEST_PROGRESS.md)
- 테스트 헬퍼 클래스 구현
  - test_helpers.dart: 기본 테스트 유틸리티
  - mock_data_helpers.dart: Mock 데이터 생성 헬퍼
  - mock_services.dart: Mock 서비스 설정 (오류 수정 완료)
  - simple_mock_services.dart: 간단한 Mock 서비스
- 단위 테스트 구현
  - CompanyListController 테스트
  - EquipmentListController 테스트
  - UserListController 테스트
- Widget 테스트 구현 (CompanyListScreen)

Mock 서비스 주요 수정사항:
- dartz import 추가
- Either 타입 제거 (실제 서비스와 일치하도록)
- 메서드 시그니처 수정 (실제 서비스 인터페이스와 일치)
- Mock 데이터 생성 메서드 추가

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 20:37:26 +09:00

5.7 KiB

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)

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 클래스 생성

flutter pub run build_runner build --delete-conflicting-outputs

📝 테스트 작성 예제

1. 컨트롤러 단위 테스트

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<CompanyService>(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 테스트

testWidgets('화면 렌더링 테스트', (WidgetTester tester) async {
  await pumpTestWidget(
    tester,
    const CompanyListRedesign(),
  );
  
  await pumpAndSettleWithTimeout(tester);
  
  expect(find.text('회사 관리'), findsOneWidget);
  expect(find.byType(TextField), findsOneWidget);
});

3. Mock 데이터 생성

// 회사 목록 생성
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

📊 테스트 커버리지

커버리지 확인

flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html

목표 커버리지

  • 단위 테스트: 80% 이상
  • Widget 테스트: 70% 이상
  • 통합 테스트: 주요 사용자 시나리오 100%

🔄 CI/CD 통합

GitHub Actions 예제

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

📚 추가 리소스

🔧 문제 해결

Mock 클래스를 찾을 수 없을 때

flutter pub run build_runner build --delete-conflicting-outputs

테스트가 타임아웃될 때

pumpAndSettleWithTimeout 헬퍼 사용:

await pumpAndSettleWithTimeout(tester, timeout: Duration(seconds: 10));

GetIt 관련 오류

setUp(() {
  getIt = setupTestGetIt(); // 반드시 첫 번째로 실행
});

tearDown(() {
  getIt.reset(); // 반드시 실행
});