Flutter测试中如何Mock SharedPreferences.getInstance()?
问题根源
你当前的测试代码无效,核心问题有两个:
SharedPreferences.getInstance()是静态方法,你Mock的是自定义MockSharedPreferences类的静态方法,但实际登录逻辑调用的是SharedPreferences原生类的getInstance(),两者不匹配。- 常规mocktail的实例Mock方式不适用于静态方法,必须通过SharedPreferences提供的初始化入口替换实现。
推荐方案:使用shared_preferences_test包
这是官方维护的测试工具,专门处理SharedPreferences的Mock,步骤如下:
- 在
pubspec.yaml的dev_dependencies中添加依赖:
dev_dependencies: shared_preferences_test: ^2.2.0 # 请使用最新版本
- 修改测试代码:
import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences_test/shared_preferences_test.dart'; import 'package:mocktail/mocktail.dart'; class MockSharedPreferences extends Mock implements SharedPreferences {} void main() { group('Login Tests', () { testWidgets('Login success saves token to SharedPreferences', (WidgetTester tester) async { // 创建Mock实例 final mockPrefs = MockSharedPreferences(); // 替换SharedPreferences.getInstance的返回值 when(() => SharedPreferences.getInstance()).thenAnswer((_) async => mockPrefs); // 需先Mock Dio的post请求(避免真实网络调用),再触发登录操作 // ... 你的登录触发逻辑 ... // 验证是否正确调用setString保存token verify(() => mockPrefs.setString('token', any())).called(1); }); }); }
备选方案:手动覆盖静态方法
如果不想添加额外依赖,可直接覆盖SharedPreferences.getInstance的实现:
import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mocktail/mocktail.dart'; class MockSharedPreferences extends Mock implements SharedPreferences {} void main() { late MockSharedPreferences mockPrefs; // 保存原getInstance方法,测试后恢复 late Future<SharedPreferences> Function() originalGetInstance; setUp(() { mockPrefs = MockSharedPreferences(); originalGetInstance = SharedPreferences.getInstance; // 替换为Mock实例 SharedPreferences.getInstance = () async => mockPrefs; }); tearDown(() { // 恢复原方法,避免影响其他测试 SharedPreferences.getInstance = originalGetInstance; }); testWidgets('Login success saves token', (WidgetTester tester) async { // 触发登录操作 // ... // 验证token保存逻辑 verify(() => mockPrefs.setString('token', 'test_token')).called(1); }); }
额外提醒
- 登录代码中的Dio网络请求必须Mock,否则测试会卡在网络调用环节或失败。
- 对于Bloc和Navigator的操作,测试时需确保Widget树包含对应的BlocProvider,或用NavigatorObserver验证导航行为,避免相关逻辑出错。
内容的提问来源于stack exchange,提问作者user19517977
相关产品推荐
相关产品推荐

