Flutter使用Provider绑定ViewModel时如何测试页面导航逻辑
解决方案
核心问题说明
你当前测试代码的主要问题有2个:
MainMenuScreen没有接收ViewModel的构造参数,你是通过Provider.of在组件内部获取实例,所以不能直接通过构造函数传入Mock实例,需要在上层用ChangeNotifierProvider包裹来提供Mock的ViewModel- 测试环境缺少本地化配置,直接构建
MaterialApp会导致AppLocalizations.of(context)返回空,无法正常渲染文本
完整测试代码
import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; // 导入你自己的项目相关类 import 'package:your_app_name/main.dart'; import 'package:your_app_name/main_menu_screen.dart'; import 'package:your_app_name/about_screen.dart'; class MockMainMenuViewModel extends Mock implements MainMenuViewModel {} class MockNavigatorObserver extends Mock implements NavigatorObserver {} void main() { group('MainMenuScreen导航测试', () { late MockNavigatorObserver mockObserver; late MockMainMenuViewModel mockViewModel; setUp(() { mockObserver = MockNavigatorObserver(); mockViewModel = MockMainMenuViewModel(); }); Future<void> buildTestApp(WidgetTester tester) async { await tester.pumpWidget( MultiProvider( providers: [ // 提供Mock的ViewModel ChangeNotifierProvider<MainMenuViewModel>.value(value: mockViewModel), // 如果其他ViewModel没有用到可以只提供需要的,或者也Mock之后加进来 ChangeNotifierProvider(create: (context) => LevelSelectionViewModel()), ChangeNotifierProvider(create: (context) => LevelViewModel()), ], child: MaterialApp( localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', ''), Locale('es', ''), ], // 注入模拟的导航观察者 navigatorObservers: [mockObserver], home: const MainMenuScreen(), ), ), ); // 等待页面渲染完成 await tester.pumpAndSettle(); } testWidgets('点击About按钮跳转到关于页面', (WidgetTester tester) async { await buildTestApp(tester); // 验证About按钮存在 final aboutBtn = find.text('About'); expect(aboutBtn, findsOneWidget); // 点击按钮 await tester.tap(aboutBtn); await tester.pumpAndSettle(); // 方式1:直接验证AboutScreen是否已渲染 expect(find.byType(AboutScreen), findsOneWidget); // 方式2:通过导航观察者验证导航事件是否触发(可选) // verify(mockObserver.didPush(any, any)); }); }); }
额外优化建议
你当前main.dart里存在重复注册MainMenuViewModel的问题:外层MultiProvider已经注册了一次,MaterialApp的home属性里又单独注册了一次,多余的注册可以删掉,修改如下:
// 原来的home部分 home: const MainMenuScreen(),
这样就不会重复创建ViewModel实例了。
后续切换为Key识别的修改点
等你给About按钮加上Key之后,只需要把查找按钮的代码改为按Key查找即可:
final aboutBtn = find.byKey(const Key('btn_about'));
内容的提问来源于stack exchange,提问作者greysqrl
相关产品推荐
相关产品推荐

