skills/flutter/references/advanced-testing.md

197 lines
4.4 KiB
Markdown

---
name: advanced-testing
description: Flutter testing - widget testing, integration testing, test utilities, and testing best practices
---
# Testing
Flutter provides comprehensive testing tools for unit, widget, and integration tests.
## Widget Testing
Test individual widgets in isolation.
```dart
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments when button is pressed', (WidgetTester tester) async {
// Build widget
await tester.pumpWidget(const MyApp());
// Find widget
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap button
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
// Verify result
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
```
## Finding Widgets
```dart
// Find by text
find.text('Hello')
find.textContaining('Hello')
// Find by type
find.byType(ElevatedButton)
find.byType(Text)
// Find by key
find.byKey(Key('my-key'))
// Find by icon
find.byIcon(Icons.star)
// Find by widget
find.byWidget(myWidget)
// Find ancestors/descendants
find.ancestor(of: find.text('Hello'), matching: find.byType(Container))
find.descendant(of: find.byType(Column), matching: find.text('Hello'))
```
## Widget Tester Methods
```dart
// Pump widget
await tester.pumpWidget(MyWidget());
// Pump frames
await tester.pump(); // One frame
await tester.pump(Duration(seconds: 1)); // Multiple frames
// Tap
await tester.tap(find.byType(ElevatedButton));
await tester.tapAt(Offset(100, 100));
// Drag
await tester.drag(find.byType(ListView), Offset(0, -100));
// Enter text
await tester.enterText(find.byType(TextField), 'Hello');
// Long press
await tester.longPress(find.byType(ElevatedButton));
// Fling
await tester.fling(find.byType(ListView), Offset(0, -100), 1000);
```
## Expectations
```dart
// Find widgets
expect(find.text('Hello'), findsOneWidget);
expect(find.text('Hello'), findsNothing);
expect(find.text('Hello'), findsWidgets);
expect(find.text('Hello'), findsNWidgets(2));
// Widget properties
final widget = tester.widget<Text>(find.text('Hello'));
expect(widget.style?.fontSize, 16);
// Widget exists
expect(find.byType(ElevatedButton), findsOneWidget);
```
## Integration Testing
Test complete app flows.
```dart
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Complete user flow', (WidgetTester tester) async {
// Start app
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
// Navigate
await tester.tap(find.text('Login'));
await tester.pumpAndSettle();
// Enter credentials
await tester.enterText(find.byKey(Key('email')), 'user@example.com');
await tester.enterText(find.byKey(Key('password')), 'password');
await tester.tap(find.text('Submit'));
await tester.pumpAndSettle();
// Verify navigation
expect(find.text('Dashboard'), findsOneWidget);
});
}
```
## Mocking
Mock dependencies for testing.
```dart
// Mock HTTP client
class MockHttpClient extends Mock implements http.Client {}
void main() {
testWidgets('Loads data from API', (WidgetTester tester) async {
final mockClient = MockHttpClient();
when(mockClient.get(any)).thenAnswer(
(_) async => http.Response('{"data": "test"}', 200),
);
await tester.pumpWidget(
MyApp(httpClient: mockClient),
);
await tester.pumpAndSettle();
expect(find.text('test'), findsOneWidget);
});
}
```
## Golden Tests
Test widget appearance.
```dart
testWidgets('Widget appearance', (WidgetTester tester) async {
await tester.pumpWidget(const MyWidget());
await expectLater(
find.byType(MyWidget),
matchesGoldenFile('golden/my_widget.png'),
);
});
```
## Key Points
- Use `testWidgets()` for widget tests
- Use `find` to locate widgets
- Use `tester.pumpWidget()` to build widgets
- Use `tester.pump()` to advance frames
- Use `expect()` with `findsOneWidget`, `findsNothing`, etc.
- Use `IntegrationTestWidgetsFlutterBinding` for integration tests
- Mock dependencies for isolated testing
- Use golden tests for visual regression testing
- Use `pumpAndSettle()` to wait for animations to complete
<!--
Source references:
- https://github.com/flutter/flutter/tree/main/packages/flutter_test
- https://docs.flutter.dev/testing
-->