You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter测试出现LateInitializationError:_prefs字段未初始化求助

Flutter测试中SharedPreferenceHelper单例未初始化导致LateInitializationError问题解决

我在Flutter项目里用单例类SharedPreferenceHelper管理SharedPreferences,主函数里已经完成初始化,但写登录页面输入验证测试用例时,ApiProvider调用SharedPreferenceHelper.getInstance()抛出LateInitializationError,提示字段_prefs@29023595未初始化。

相关代码

主函数(main.dart)

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SharedPreferenceHelper.initPreference();
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ThemeProvider(),),
        ChangeNotifierProvider(create: (_) => ApiProvider(),),
      ],
      child: const MyApp()
    )
  );
}

SharedPreferenceHelper实现

class SharedPreferenceHelper {
  static late SharedPreferences _prefs;

  static Future<void> initPreference() async {
    _prefs = await SharedPreferences.getInstance();
  }

  static SharedPreferences getInstance() => _prefs;
}

测试代码

testWidgets("Validate Signin field with different input", (WidgetTester tester) async {
  await tester.pumpWidget(
    MultiProvider(
      providers: [
          ChangeNotifierProvider(create: (_) => ThemeProvider()),
          ChangeNotifierProvider(create: (_) => ApiProvider()),
        ],
      child: const MaterialApp(
        home: SigninScreen(),
       )
      )
    );
  
  // 输入无效文本
  await tester.enterText(find.byKey(const Key("mobile_field")), "123343");
  await tester.tap(find.byType(ButtonWidget));
  await tester.pumpAndSettle();
  expect(find.text("Enter a valid user ID"), findsOneWidget);

  // 测试空字符串
  await tester.enterText(find.byKey(const Key("mobile_field")), "");
  await tester.tap(find.byType(ButtonWidget));
  await tester.pump();
  expect(find.text("User ID is required"), findsOneWidget);
  
  // 测试有效输入
  await tester.enterText(find.byKey(const Key("mobile_field")), "9876543210");
  await tester.tap(find.byType(ButtonWidget));
  await tester.pump();
  expect(find.byKey(const Key("home_screen")), findsOneWidget);
});

错误信息

class ApiProvider extends ChangeNotifier{
  // shared preference实例
  final SharedPreferences _prefs = SharedPreferenceHelper.getInstance();
}

The following LateError was thrown building Consumer<ApiProvider>(dirty, dependencies:
[_InheritedProviderScope<ApiProvider?>]):
LateInitializationError: Field '_prefs@29023595' has not been initialized.

The relevant error-causing widget was:
  Consumer<ApiProvider> Consumer:file:///D:/Projects/kitafeedback/lib/screens/home_screen.dart:43:13

When the exception was thrown, this was the stack:
#0      SharedPreferenceHelper._prefs (package:kitafeedback/common/shared_preference_helper.dart)
#1      SharedPreferenceHelper.getInstance (package:kitafeedback/common/shared_preference_helper.dart:10:45)
#2      new ApiProvider (package:kitafeedback/API/api_provider.dart:18:59)

问题原因

测试代码未调用SharedPreferenceHelper.initPreference()初始化_prefs字段,直接创建ApiProvider时会调用getInstance()访问未初始化的late变量,触发报错。主函数里的初始化逻辑不会在测试环境自动执行,测试需单独处理依赖初始化。

解决方案

方案1:测试用例中提前初始化SharedPreferenceHelper

在测试用例开头添加初始化代码,确保_prefs被正确赋值:

testWidgets("Validate Signin field with different input", (WidgetTester tester) async {
  // 先初始化SharedPreferenceHelper
  WidgetsFlutterBinding.ensureInitialized();
  await SharedPreferenceHelper.initPreference();

  await tester.pumpWidget(
    MultiProvider(
      providers: [
          ChangeNotifierProvider(create: (_) => ThemeProvider()),
          ChangeNotifierProvider(create: (_) => ApiProvider()),
        ],
      child: const MaterialApp(
        home: SigninScreen(),
       )
      )
    );
  
  // 后续测试逻辑不变
});

方案2:用Mock替代真实SharedPreferences(推荐)

测试无需真实存储实例,用mockito创建Mock对象避免依赖真实存储:

  1. 添加依赖到pubspec.yaml的dev_dependencies:
dev_dependencies:
  mockito: ^5.4.0
  build_runner: ^2.4.4
  1. 生成Mock类:
flutter pub run build_runner build
  1. 修改测试用例和ApiProvider:
import 'package:mockito/mockito.dart';

class MockSharedPreferences extends Mock implements SharedPreferences {}

testWidgets("Validate Signin field with different input", (WidgetTester tester) async {
  // 创建Mock实例
  final mockPrefs = MockSharedPreferences();
  
  await tester.pumpWidget(
    MultiProvider(
      providers: [
          ChangeNotifierProvider(create: (_) => ThemeProvider()),
          ChangeNotifierProvider(create: (_) => ApiProvider(prefs: mockPrefs)),
        ],
      child: const MaterialApp(
        home: SigninScreen(),
       )
      )
    );
  
  // 后续测试逻辑不变
});

同时修改ApiProvider支持构造函数注入:

class ApiProvider extends ChangeNotifier{
  final SharedPreferences _prefs;

  // 支持传入自定义SharedPreferences,方便测试
  ApiProvider({SharedPreferences? prefs}) : _prefs = prefs ?? SharedPreferenceHelper.getInstance();
}

方案3:优化SharedPreferenceHelper初始化逻辑

避免使用late变量,改用异步初始化并提供清晰错误提示:

class SharedPreferenceHelper {
  static SharedPreferences? _prefs;

  static Future<void> initPreference() async {
    _prefs ??= await SharedPreferences.getInstance();
  }

  static SharedPreferences getInstance() {
    if (_prefs == null) {
      throw StateError("SharedPreferenceHelper未初始化,请先调用initPreference()");
    }
    return _prefs!;
  }
}

内容的提问来源于stack exchange,提问作者Karthikn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:48:22