Flutter Testing — Flutter 测试
v1.0.0Flutter 测试工具。
详细分析 ▾
运行时依赖
版本
Initial release of openclaw-flutter-testing. - Provides comprehensive guidance for all types of Flutter tests: unit, widget, and integration. - Includes quick start code examples and running instructions for each test type. - Explains best practices, testing workflows, and decision tree for choosing test strategies. - Offers advanced tips for mocking, test patterns, and handling plugins in tests. - Summarizes test trade-offs, build modes, and critical testing concepts in Flutter.
安装命令 点击复制
技能文档
Overview
This skill provides comprehensive guidance for testing Flutter applications across all test types. Flutter testing falls into three categories:
- Unit tests - Test individual functions, methods, 或 classes 在...中 isolation
- Widget tests (组件 tests) - Test single widgets 和 验证 UI appearance 和 behavior
- Integration tests - Test complete apps 或 large parts 到 验证 end-到-end functionality
A well-tested Flutter app has many unit and widget tests for code coverage, plus enough integration tests to cover important use cases.
Test 类型 Trade-offs
| Tradeoff | Unit | Widget | Integration |
|---|---|---|---|
| Confidence | Low | Higher | Highest |
| Maintenance cost | Low | Higher | Highest |
| Dependencies | Few | More | Most |
| Execution speed | Quick | Quick | Slow |
Build Modes 对于 Testing
Flutter supports three build modes with different implications for testing:
- Debug mode - 使用 期间 development 带有 hot 重新加载. Assertions 已启用, debugging 已启用, 但是 performance janky
- 个人资料 mode - 使用 对于 performance analysis. Similar 到 release mode 但是 带有 一些 debugging features 已启用
- Release mode - 使用 对于 deployment. Assertions 已禁用, optimized 对于 speed 和 size
Quick 开始
Unit Tests
Unit tests test a single function, method, or class. Mock external dependencies and avoid disk I/O or UI rendering.
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);
});
}
Run with: flutter test
Widget Tests
Widget tests test single widgets to verify UI appearance and interaction.
import '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);
});
}
Integration Tests
Integration tests test complete apps on real devices or emulators.
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);
});
}
Run with: flutter test integration_test/
Testing Workflow Decision Tree
- 什么 您 testing?
- 做 depend 在...上 plugins/native code?
- 需要 到 mock dependencies?
- Encountering errors?
Unit Tests
Unit tests verify the correctness of a unit of logic under various conditions.
当...时 到 使用 Unit Tests
- Testing business logic functions
- Validating data transformations
- Testing state management logic
- Mocking external services/API calls
键 Concepts
- 使用
包:test/test.dart - Mock dependencies 使用 Mockito 或 similar
- Avoid file I/O 或 UI rendering
- Fast execution, high maintainability
Advanced Unit Testing
For mocking dependencies, plugin interactions, and complex scenarios, see Unit Testing Reference.
Widget Tests
Widget tests verify widget UI appearance and behavior in a test environment.
当...时 到 使用 Widget Tests
- Testing widget rendering
- Verifying 用户 interactions (taps, drags, scrolling)
- Testing 不同 orientations
- Validating widget state changes
Widget Testing Patterns
Finding Widgets
// 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);
用户 Interactions
// 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();
Testing 不同 Orientations
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));
});
Advanced Widget Testing
For scrolling, complex interactions, and performance testing, see Widget Testing Reference.
Integration Tests
Integration tests test complete apps or large parts on real devices or emulators.
当...时 到 使用 Integration Tests
- Testing complete 用户 flows
- Verifying multiple screens/pages
- Testing 导航 flows
- Performance profiling
Integration Test Structure
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);
});
});
}
Performance Testing
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));
});
Advanced Integration Testing
For performance profiling, CI integration, and complex scenarios, see Integration Testing Reference.
Plugins 在...中 Tests
When testing code that uses plugins, special handling is required to avoid crashes.
Testing App Code 带有 Plugins
If your Flutter app uses plugins, you need to mock the platform channel calls in unit/widget tests.
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,
);
});
}
Testing Plugins
For comprehensive guidance on testing Flutter plugins (including native code), see Plugin Testing Reference.
Common Testing Errors
' RenderFlex overflowed...'
Yellow and black stripes indicate overflow. Usually caused by unconstrained children in Row/Column.
Solution: Wrap overflowing widget 在...中 Expanded 或 Flexible.
// 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...')])),
],
)
'Vertical viewport 是 given unbounded height'
Occurs when ListView (or other scrollable) is inside Column without height constraints.
Solution: Wrap 在...中 Expanded 或 使用 shrinkWrap: 真.
// Problem
Column(
children: [
Text('Header'),
ListView(children: [...]), // Error!
],
)// Solution
Column(
children: [
Text('Header'),
Expanded(child: ListView(children: [...])), ],
)
'setState called 期间 build'
Never call setState during build method.
Solution: 使用 Navigator API 或 defer 到 post-build 回调.
For more errors and solutions, see Common Errors Reference.
Testing Best Practices
- Test Pyramid - 更多 unit/widget tests, fewer integration tests
- Descriptive Test Names - Names 应该 clearly describe 什么 和 为什么
- Arrange-Act-Assert - Structure tests 带有 清除 sections
- Avoid Test Interdependence - 每个 test 应该 independent
- Mock External Dependencies - Keep tests fast 和 reliable
- Run Tests 在...中 CI - Automate testing 在...上 every 推送
Running Tests
Run 所有 Tests
flutter test
Run Specific Test File
flutter test test/widget_test.dart
Run Integration Tests
flutter test integration_test/
Run 带有 Coverage
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
Run Tests 在...上 不同 Platforms
# Android
flutter test --platform android# iOS
flutter test --platform ios
# Web
flutter test --platform chrome
Debugging Tests
Debug Test
flutter test --no-sound-null-safety test/my_test.dart
Verbose 输出
flutter test --verbose
Run Specific Test
flutter test --name "Counter value should be incremented"
Resources
Reference Files
- Unit Testing Guide - 在...中-depth unit testing patterns 和 mocking strategies
- Widget Testing Guide - Widget finding, interactions, 和 advanced scenarios
- Integration Testing Guide - End-到-end testing 和 performance profiling
- Mocking Guide - Mocking dependencies 和 插件 interactions
- Common Errors - Solutions 对于 frequent testing errors
- 插件 Testing - Testing Flutter plugins 带有 native code
External Resources
免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制