测试的价值不是“覆盖率”,而是降低回归成本。本文给出一套可落地的 Flutter 测试分层策略与代码范式。
1. 测试分层:三层足够
推荐分成三层:
- 单元测试:纯逻辑,快而稳定
- 组件测试:Widget 行为与 UI
- 集成测试:关键业务流程
不要试图用一种测试覆盖所有问题。
2. 单元测试:把业务逻辑抽出来
class PriceCalculator {
double discount(double price, double rate) => price * (1 - rate);
}
void main() {
test('discount applies correctly', () {
final calc = PriceCalculator();
expect(calc.discount(100, 0.2), 80);
});
}
单元测试应该独立于 Flutter 环境,保证速度快。
3. 组件测试:验证 UI 行为
testWidgets('button triggers callback', (tester) async {
var tapped = false;
await tester.pumpWidget(
MaterialApp(
home: ElevatedButton(
onPressed: () => tapped = true,
child: const Text('Tap'),
),
),
);
await tester.tap(find.text('Tap'));
await tester.pump();
expect(tapped, true);
});
组件测试验证的是 UI 行为,而不是内部实现。
4. 集成测试:覆盖关键流程
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('login flow', (tester) async {
await tester.pumpWidget(const MyApp());
await tester.enterText(find.byKey(const Key('account')), 'user');
await tester.enterText(find.byKey(const Key('password')), '123');
await tester.tap(find.text('Login'));
await tester.pumpAndSettle();
expect(find.text('Home'), findsOneWidget);
});
}
集成测试不求多,但必须覆盖核心路径。
5. Mock 与依赖隔离
让测试稳定的关键是隔离外部依赖:
- 网络请求用 mock
- 本地存储用 fake
- 时间与随机数可注入
推荐通过依赖注入来切换测试实现。
6. CI 中的测试策略
- 单元测试每次提交必跑
- 组件测试在 PR 中跑
- 集成测试夜间或主分支跑
7. 测试清单
- 单元测试覆盖核心逻辑
- 组件测试覆盖关键交互
- 集成测试覆盖核心流程
- Mock 外部依赖
- CI 自动执行
总结
测试不是成本,而是长期效率。分层测试可以让团队在复杂度上保持安全边界。