Loading...
Loading...
Comprehensive Flutter testing guidance covering unit tests, widget tests, and integration tests. Use when working with Flutter applications to write unit tests for functions/methods/classes, create widget tests to verify UI components, develop integration tests for end-to-end testing, mock dependencies and plugin interactions, debug common testing errors, test Flutter plugins with native code, and run tests in different build modes (debug, profile, release)
npx skill4agent add madteacher/mad-agents-skills flutter-testing| Tradeoff | Unit | Widget | Integration |
|---|---|---|---|
| Confidence | Low | Higher | Highest |
| Maintenance cost | Low | Higher | Highest |
| Dependencies | Few | More | Most |
| Execution speed | Quick | Quick | Slow |
import 'package:test/test.dart';
import 'package:my_app/counter.dart';
void main() {
test('Counter value should be incremented', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}flutter testimport 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('MyWidget has a title and message', (tester) async {
await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
final titleFinder = find.text('T');
final messageFinder = find.text('M');
expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('tap button, verify counter', (tester) async {
await tester.pumpWidget(const MyApp());
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byKey(const ValueKey('increment')));
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget);
});
}flutter test integration_test/package:test/test.dart// By text
final titleFinder = find.text('Title');
// By widget type
final buttonFinder = find.byType(ElevatedButton);
// By key
final fabFinder = find.byKey(const ValueKey('increment'));
// By widget instance
final myWidgetFinder = find.byWidget(myWidgetInstance);// Tap
await tester.tap(buttonFinder);
// Drag
await tester.drag(listFinder, const Offset(0, -300));
// Enter text
await tester.enterText(fieldFinder, 'Hello World');
// Scroll
await tester.fling(listFinder, const Offset(0, -500), 10000);
await tester.pumpAndSettle();testWidgets('widget in landscape mode', (tester) async {
// Set to landscape
await tester.binding.setSurfaceSize(const Size(800, 400));
await tester.pumpWidget(const MyApp());
// Verify landscape behavior
expect(find.byType(MyWidget), findsOneWidget);
// Reset to portrait
addTearDown(tester.binding.setSurfaceSize(null));
});void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('end-to-end test', () {
testWidgets('complete user flow', (tester) async {
await tester.pumpWidget(const MyApp());
// Step 1: Navigate to screen
await tester.tap(find.text('Login'));
await tester.pumpAndSettle();
// Step 2: Enter credentials
await tester.enterText(find.byKey(const Key('username')), 'user');
await tester.enterText(find.byKey(const Key('password')), 'pass');
// Step 3: Submit
await tester.tap(find.text('Submit'));
await tester.pumpAndSettle();
// Verify result
expect(find.text('Welcome'), findsOneWidget);
});
});
}testWidgets('scrolling performance', (tester) async {
await tester.pumpWidget(const MyApp());
final listFinder = find.byType(ListView);
// Measure performance
final timeline = await tester.trace(() async {
await tester.fling(listFinder, const Offset(0, -500), 10000);
await tester.pumpAndSettle();
});
// Analyze timeline data
expect(timeline.frames.length, greaterThan(10));
});import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
// Mock platform channel
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(
const MethodChannel('your.plugin.channel'),
(MethodCall methodCall) async {
if (methodCall.method == 'getPlatformVersion') {
return 'Android 12';
}
return null;
},
);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(
const MethodChannel('your.plugin.channel'),
null,
);
});
}ExpandedFlexible// Problem
Row(
children: [
Icon(Icons.message),
Column(children: [Text('Very long text...')]), // Overflow!
],
)
// Solution
Row(
children: [
Icon(Icons.message),
Expanded(child: Column(children: [Text('Very long text...')])),
],
)ExpandedshrinkWrap: true// Problem
Column(
children: [
Text('Header'),
ListView(children: [...]), // Error!
],
)
// Solution
Column(
children: [
Text('Header'),
Expanded(child: ListView(children: [...])),
],
)flutter testflutter test test/widget_test.dartflutter test integration_test/flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html# Android
flutter test --platform android
# iOS
flutter test --platform ios
# Web
flutter test --platform chromeflutter test --no-sound-null-safety test/my_test.dartflutter test --verboseflutter test --name "Counter value should be incremented"