반응형

플러터(Flutter) 앱의 품질과 신뢰성을 높이기 위해서는 단위 테스트(Unit Test), 위젯 테스트(Widget Test), 통합 테스트(Integration Test)를 체계적으로 수행하는 것이 필수입니다.
각 테스트의 목적, 작성 방법, 실전 팁을 한눈에 정리합니다.
단위 테스트 (Unit Test)
개념
- 코드의 가장 작은 단위(함수, 클래스 등)를 격리하여 동작을 검증하는 테스트
- 외부 UI, DB, 네트워크 등과 무관하게 로직 자체만 검증
장점
- 코드 신뢰성·유지보수성 향상
- 리팩토링 시 안정성 보장
- 문서화 및 협업 기준 제공
작성 방법
- test 폴더에 _test.dart 파일 생성
- flutter_test 패키지(dev_dependencies) 사용
- test() 함수와 expect()로 결과 검증
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter.dart';
void main() {
test('Counter의 초기값은 0이어야 한다', () {
final counter = Counter();
expect(counter.value, 0);
});
test('increment() 호출 시 값이 1 증가해야 한다', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}터미널에서 flutter test로 실행
위젯 테스트 (Widget Test)
개념
- 하나의 위젯(컴포넌트) 단위로 UI, 상호작용, 상태 변화를 검증
- 실제 렌더링 없이 가상 환경에서 동작(빠르고 효율적)
작성 방법
- flutter_test 패키지의 testWidgets() 사용
- WidgetTester로 위젯 빌드, 상호작용(pump, tap 등) 시뮬레이션
- find, expect 등으로 결과 검증
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart';
void main() {
testWidgets('카운터 증가 버튼 테스트', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// 초기값 0 확인
expect(find.text('0'), findsOneWidget);
// + 버튼 클릭
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// 값이 1로 변경됐는지 확인
expect(find.text('1'), findsOneWidget);
});
}- pumpWidget: 위젯 트리 빌드
- tap, pump: 상호작용 및 상태 반영
통합 테스트 (Integration Test)
개념
- 실제 디바이스/에뮬레이터에서 앱의 여러 위젯·기능을 엔드 투 엔드(End-to-End)로 검증
- 사용자 시나리오(로그인, 화면 전환, 데이터 처리 등) 전체 흐름 테스트
작성 방법
- integration_test 패키지 사용 (integration_test 폴더 내 _test.dart 파일 작성)
- 실제 앱 실행, UI 상호작용, 결과 검증
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('로그인 후 메인화면 진입', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
// 로그인 입력 및 버튼 클릭
await tester.enterText(find.byKey(Key('email')), 'test@example.com');
await tester.enterText(find.byKey(Key('password')), '1234');
await tester.tap(find.text('로그인'));
await tester.pumpAndSettle();
// 메인화면 진입 확인
expect(find.text('메인화면'), findsOneWidget);
});
}- 실제 앱 구동, 여러 화면 및 기능 연동 테스트
- pumpAndSettle: 모든 애니메이션·상태 변화 완료까지 대기
비교 요약 및 실전 팁
| 단위 테스트 | 함수/클래스 | 매우 빠름 | 로직 검증, 리팩토링 |
| 위젯 테스트 | 단일 위젯 | 빠름 | UI/상호작용, 상태 변화 |
| 통합 테스트 | 전체 앱/흐름 | 느림 | 실제 사용자 시나리오 |
실전 팁
- 테스트 커버리지: 핵심 로직, UI, 주요 시나리오 모두 포함
- Mock/Stub 활용: 외부 의존성 격리(특히 단위 테스트)
- CI/CD 연동: 자동화로 배포 전 품질 확보
- 테스트는 test, integration_test 폴더에 별도 관리
- 테스트 함수명, 설명 명확히 작성
고급 테스트 패턴
// Mock 객체 활용 예시
class MockApiService extends Mock implements ApiService {}
void main() {
test('API 호출 성공 시 데이터 반환', () async {
final mockApi = MockApiService();
when(mockApi.fetchData()).thenAnswer((_) async => 'test data');
final service = DataService(mockApi);
final result = await service.getData();
expect(result, 'test data');
});
}마무리
플러터의 단위 테스트, 위젯 테스트, 통합 테스트를 적절히 조합하면 앱의 신뢰성과 유지보수성을 크게 높일 수 있습니다. 작은 코드부터 전체 사용자 흐름까지 꼼꼼하게 검증하는 습관이 고품질 앱 개발의 지름길입니다.
테스트 피라미드를 고려하여 단위 테스트를 가장 많이, 통합 테스트를 적절히 배치하고, 지속적인 테스트 자동화를 통해 안정적인 앱 개발 환경을 구축해보세요.
반응형
'IT기술 > 플러터 (flutter)' 카테고리의 다른 글
| Flutter Method Channel 완벽 가이드: 네이티브 코드와 양방향 통신 구현하기 (2) | 2025.07.15 |
|---|---|
| Flutter 앱 스토어 배포 완벽 가이드: 구글 플레이스토어 & 애플 앱스토어 등록 방법 (8) | 2025.07.13 |
| Flutter 애니메이션 완벽 가이드: 기본부터 고급 활용법까지 (4) | 2025.07.11 |
| Flutter UI/UX 디자인 완벽 가이드: 반응형 레이아웃, 다크모드, 테마 적용 (0) | 2025.07.10 |
| Flutter 화면 전환과 데이터 전달 완벽 가이드: Navigator 활용법부터 고급 라우팅까지 (2) | 2025.07.09 |