Flutter는 테스트 도구를 SDK에 기본으로 포함합니다. 테스트는 범위에 따라 세 가지로 나뉩니다. 단위 테스트는 함수나 클래스 하나를, 위젯 테스트는 위젯 하나 또는 작은 화면을, 통합 테스트는 실제 기기나 에뮬레이터에서 앱 전체를 검사합니다. 아래로 갈수록 실제에 가깝지만 느리므로, 단위·위젯 테스트를 많이 두고 통합 테스트는 핵심 흐름에만 씁니다.
단위 테스트
테스트 파일은 test 폴더에 두고 이름을 _test.dart로 끝냅니다. Flutter 프로젝트에서는 flutter_test 패키지가 test, group, expect 같은 함수를 함께 제공합니다.
// lib/cart.dart
class Cart {
final Map<String, int> _prices = {};
void add(String name, int price) => _prices[name] = price;
int get total => _prices.values.fold(0, (sum, price) => sum + price);
}
// test/cart_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:hello_app/cart.dart';
void main() {
group('Cart', () {
test('처음에는 합계가 0이다', () {
expect(Cart().total, 0);
});
test('상품을 추가하면 합계가 늘어난다', () {
final cart = Cart()
..add('사과', 1000)
..add('배', 2500);
expect(cart.total, 3500);
});
});
}
테스트는 명령줄이나 편집기에서 실행합니다.
# 모든 테스트 실행
flutter test
# 파일 하나만 실행
flutter test test/cart_test.dart
# 이름으로 골라 실행
flutter test --name "합계"
# 커버리지 수집(coverage/lcov.info 생성)
flutter test --coverage
위젯 테스트
위젯 테스트는 testWidgets로 작성합니다. WidgetTester로 위젯을 화면에 올리고(pumpWidget), 찾고(find), 누른 뒤(tap), 다시 그리게 하고(pump), 결과를 확인합니다. 새 프로젝트의 test/widget_test.dart가 바로 이런 테스트입니다.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hello_app/main.dart';
void main() {
testWidgets('더하기 버튼을 누르면 숫자가 올라간다', (WidgetTester tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
자주 쓰는 도구는 다음과 같습니다.
find.text, find.byType, find.byIcon, find.byKey: 위젯 찾기. 테스트에서 찾기 쉽도록 위젯에 Key('submit') 같은 키를 붙여 둘 수 있습니다.findsOneWidget, findsNothing, findsNWidgets(n): 찾은 개수 확인tester.enterText(finder, '글자'): 입력란에 글자 넣기tester.pumpAndSettle(): 애니메이션이 모두 끝날 때까지 다시 그리기
의존성 바꿔 끼우기
네트워크를 쓰는 코드를 테스트할 때는 실제 서버 대신 가짜 응답을 씁니다. http 패키지는 테스트용 MockClient를 제공하므로, 함수가 http.Client를 인자로 받도록 만들면 쉽게 바꿔 끼울 수 있습니다. 더 복잡한 경우에는 mocktail이나 mockito 패키지로 가짜 객체를 만듭니다.
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:flutter_test/flutter_test.dart';
Future<String> fetchTitle(http.Client client) async {
final response = await client.get(Uri.parse('https://example.com/title'));
return response.body;
}
void main() {
test('서버 응답의 본문을 돌려준다', () async {
final client = MockClient((request) async => http.Response('Flutter', 200));
expect(await fetchTitle(client), 'Flutter');
});
}
통합 테스트
통합 테스트는 SDK에 포함된 integration_test 패키지로 작성하며, 실제 기기·에뮬레이터·데스크톱에서 앱을 실행해 위젯 테스트와 같은 API로 조작합니다. 먼저 개발용 의존성을 추가합니다.
flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
테스트 파일은 프로젝트 루트의 integration_test 폴더에 둡니다.
// integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:hello_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('앱 전체 흐름', (tester) async {
app.main();
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget);
});
}
# 연결된 기기에서 실행
flutter test integration_test/app_test.dart
# 기기를 지정
flutter test integration_test -d windows
정리
- 단위 테스트는 로직을, 위젯 테스트는 화면 동작을, 통합 테스트는 실제 기기에서 앱 전체를 검사합니다.
- 모든 테스트는
flutter test로 실행하며 --coverage로 커버리지를 모을 수 있습니다. - 위젯 테스트는
pumpWidget, find, tap, pump, expect의 흐름으로 작성합니다. - 외부 의존성은 생성자나 인자로 받아 테스트에서 가짜로 바꿔 끼울 수 있게 설계합니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.