Flutter测试按钮启用禁用及pop导航返回功能失败如何解决
问题修复方案
你的测试代码存在3个核心错误:
- 输入文本后未触发UI重建,直接读取按钮状态还是修改输入前的禁用状态,导致
expect(btn.enabled, true)报错 - 验证
navigationService.pop()调用的时机错误,放在了点击按钮之前,此时pop逻辑还未执行,必然验证失败 - 测试页面未包裹在正常的导航路由栈中,部分导航封装类在根页面调用pop时不会触发对应方法(可选优化项)
修正后的测试代码
testWidgets('Test pop navigation', (WidgetTester tester) async { final loginBloc = LoginBlocMock(); final state = getLoggedState(); whenListen( loginBloc, Stream.fromIterable( [state], ), initialState: state, ); await tester.pumpWidget( UIWrapper.wrapTranslated( UIWrapper.blocWrap( UIWrapper.themeWrap( // 优化:将EditNameScreen用MaterialApp包裹并作为push的页面,保证导航栈正常 MaterialApp( home: Scaffold( body: Builder( builder: (context) => ElevatedButton( onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (context) => EditNameScreen()), ), child: Text('to edit'), ), ), ), ), ), [ BlocProvider<LoginBloc>.value(value: loginBloc), ], ), ), ); // 先跳转到EditNameScreen页面,保证导航栈存在 await tester.tap(find.text('to edit')); await tester.pumpAndSettle(); final nameFormField = find.byKey(Key('FirstName')); await tester.enterText(nameFormField, 'John'); final lastNameFormField = find.byKey(Key('LastName')); await tester.enterText(lastNameFormField, 'Doe'); // 关键:输入完成后触发UI重建,刷新按钮状态 await tester.pump(); expect(find.byKey(Key('FirstName')), findsOneWidget); expect(find.byKey(Key('LastName')), findsOneWidget); var btn = tester.firstWidget<ElevatedButton>(find.byKey(Key('UpdateButton'))); expect(btn.enabled, true); // 先点击按钮,触发pop逻辑 await tester.tap(find.byWidget(btn)); await tester.pumpAndSettle(); // 再验证pop是否被调用 verify(navigationService.pop()).called(1); });
修改点说明
- 输入后加
await tester.pump():enterText只会修改输入框的状态,不会主动触发Widget重建,必须调用pump通知框架刷新UI,按钮的启用状态才会更新 - 调整verify和tap的顺序:必须先触发按钮点击的逻辑,再验证
pop方法的调用次数,否则验证的是点击前的调用状态,必然返回0次调用导致报错 - 补充导航栈初始化:如果你的
navigationService.pop()是基于Flutter原生Navigator封装的,直接将EditNameScreen作为根页面时调用pop不会触发任何路由操作,所以需要先将测试页面推入导航栈中,保证pop逻辑可以正常执行
内容的提问来源于stack exchange,提问作者thays garcia
相关产品推荐
相关产品推荐

