Flutter中如何测试延迟3秒渲染的Container组件?
场景
页面包含两个按钮:
- 点击第一个按钮,立即渲染蓝色Container
- 点击第二个按钮,延迟3秒后渲染红色Container
代码
loginpage_test.dart
void main() { TestWidgetsFlutterBinding.ensureInitialized(); testWidgets('test for blue and red boxes', (tester) async { // Arrange await tester.pumpWidget(const MainApp()); await tester.pumpWidget(const MaterialApp( home: DashboardPage(), )); // Act Finder blueButtonFinder = find.byKey(const ValueKey('BlueButton')); Finder blueBoxFinder = find.byKey(const ValueKey('BlueBox')); Finder redButtonFinder = find.byKey(const ValueKey('RedButton')); Finder redBoxFinder = find.byKey(const ValueKey('RedBox')); // Assert expect(blueButtonFinder, findsOneWidget); expect(blueBoxFinder, findsNothing); expect(redButtonFinder, findsOneWidget); expect(redBoxFinder, findsNothing); await tester.tap(blueButtonFinder); await tester.pumpAndSettle(); expect(blueBoxFinder, findsOneWidget); await tester.runAsync(() async { await tester.tap(redButtonFinder); // await tester.binding.delayed(const Duration(seconds: 3)); await tester.pumpAndSettle(); // await tester.pump(Duration(seconds: 3)); }); expect(redBoxFinder, findsOneWidget); }); }
dashboardpage.dart
class DashboardPage extends StatefulWidget { const DashboardPage({super.key}); @override State<DashboardPage> createState() => _DashboardPageState(); } class _DashboardPageState extends State<DashboardPage> { bool isShowBlue = false; bool isShowRed = false; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.black20, appBar: AppBar( leading: Icon(Icons.menu_rounded, size: 24.w), actions: AppbarActions.appBarActions, backgroundColor: Colors.transparent, elevation: 0, systemOverlayStyle: CustomOverlays.appbarOverlayLight, ), body: Padding( padding: EdgeInsets.symmetric(horizontal: 16.w), child: Column( children: [ CoverPictureSection(), SizedBox(height: 10.h), ElevatedButton( key: const ValueKey('BlueButton'), onPressed: () { setState(() { isShowBlue = true; }); }, child: const Text('Create Blue Box'), ), SizedBox(height: 10.h), isShowBlue ? Container( key: const ValueKey('BlueBox'), width: 50.w, height: 50.h, color: Colors.blue, ) : const SizedBox.shrink(), SizedBox(height: 10.h), ElevatedButton( key: const ValueKey('RedButton'), onPressed: () async { await Future.delayed(const Duration(seconds: 3)); setState(() { isShowRed = true; }); }, child: const Text('Create Red Box'), ), SizedBox(height: 10.h), isShowRed ? Container( key: const ValueKey('RedBox'), width: 50.w, height: 50.h, color: Colors.red, ) : const SizedBox.shrink(), ], ), ), ); } }
问题
蓝色盒子的测试可以成功,但红色盒子的测试失败,报错信息如下:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching candidate
Actual: _KeyWidgetFinder:<Found 0 widgets with key [<'RedBox'>]: []>
Which: means none were found but one was expected
断言红色盒子存在时,对应的延迟Future还未完成。尝试将tester.tap放入runAsync()中,仍无法解决问题。
解决方案
测试延迟渲染组件的核心是让测试框架等待延迟完成并触发UI更新,具体修改如下:
1. 调整测试代码中的延迟处理
移除runAsync(),直接在点击红色按钮后调用tester.pump()传入延迟时长,再用tester.pumpAndSettle()确保UI更新完成:
// 替换原有的runAsync代码块 await tester.tap(redButtonFinder); // 推进测试时间到延迟结束(无需真实等待3秒,测试框架会加速时间) await tester.pump(const Duration(seconds: 3)); // 等待所有UI更新和动画完成 await tester.pumpAndSettle(); expect(redBoxFinder, findsOneWidget);
2. 完整修改后的测试代码
void main() { TestWidgetsFlutterBinding.ensureInitialized(); testWidgets('test for blue and red boxes', (tester) async { // Arrange await tester.pumpWidget(const MainApp()); await tester.pumpWidget(const MaterialApp( home: DashboardPage(), )); // Act Finder blueButtonFinder = find.byKey(const ValueKey('BlueButton')); Finder blueBoxFinder = find.byKey(const ValueKey('BlueBox')); Finder redButtonFinder = find.byKey(const ValueKey('RedButton')); Finder redBoxFinder = find.byKey(const ValueKey('RedBox')); // Assert expect(blueButtonFinder, findsOneWidget); expect(blueBoxFinder, findsNothing); expect(redButtonFinder, findsOneWidget); expect(redBoxFinder, findsNothing); await tester.tap(blueButtonFinder); await tester.pumpAndSettle(); expect(blueBoxFinder, findsOneWidget); // 修改后的红色按钮测试逻辑 await tester.tap(redButtonFinder); await tester.pump(const Duration(seconds: 3)); await tester.pumpAndSettle(); expect(redBoxFinder, findsOneWidget); }); }
内容的提问来源于stack exchange,提问作者Ayan Dasgupta
相关产品推荐
相关产品推荐

