Flutter单元测试使用Provider报错:空值检查运算符用在空值上
解决Flutter单元测试中Provider空值检查错误的问题
错误原因
你遇到的Null check operator used on a null value错误,本质是因为你使用的MockBuildContext并没有注册StudentProvider实例。Provider.of需要从上下文的祖先组件树中查找对应的Provider,但你的Mock上下文不属于任何包含StudentProvider的组件树,因此返回null,触发空值检查失败。
另外你的测试代码存在两处笔误:
saveStuden应为saveStudentsets应为定义好的sts列表
解决方案
方案1:使用ProviderContainer(推荐,纯单元测试无需Widget树)
从provider包(版本≥6.0.0)提供的ProviderContainer可以直接管理Provider实例,无需依赖Widget上下文,更适合单元测试场景:
import 'package:provider/provider.dart'; import 'package:test/test.dart'; void main() { late ProviderContainer container; late StudentProvider studentProvider; setUp(() { // 初始化Provider容器,注册StudentProvider container = ProviderContainer( overrides: [ ChangeNotifierProvider<StudentProvider>( create: (_) => StudentProvider(), ), ], ); // 获取Provider实例 studentProvider = container.read<StudentProvider>(); }); tearDown(() { // 清理容器,避免测试间状态污染 container.dispose(); }); test('测试学生控制器添加新学生', () async { List<Students> sts = [ Students(name: 'Barbels', age: 21, weight: 70), Students(name: 'Hazel', age: 31, weight: 60), ]; var id = '1'; // 修改MyController.saveStudent方法,直接接收StudentProvider实例(更易测试) MyController.saveStudent(studentProvider, id, sts); // 验证结果 expect(studentProvider.items.length, equals(2)); }); }
如果无法修改MyController.saveStudent的参数,你可以通过container.context获取一个绑定了Provider的上下文:
final context = container.context; MyController.saveStudent(context, id, sts);
方案2:Widget测试(使用真实上下文)
如果必须依赖Widget上下文,可以通过testWidgets构建包含StudentProvider的组件树:
import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; void main() { testWidgets('测试学生控制器添加新学生', (tester) async { // 构建包含StudentProvider的Widget树 await tester.pumpWidget( ChangeNotifierProvider( create: (context) => StudentProvider(), child: const MaterialApp(home: Scaffold(body: SizedBox())), ), ); List<Students> sts = [ Students(name: 'Barbels', age: 21, weight: 70), Students(name: 'Hazel', age: 31, weight: 60), ]; var id = '1'; // 获取真实上下文 final context = tester.element(find.byType(SizedBox)); MyController.saveStudent(context, id, sts); // 验证Provider中的数据 final provider = Provider.of<StudentProvider>(context, listen: false); expect(provider.items.length, equals(2)); }); }
额外注意事项
- 避免使用
setUpAll初始化测试依赖,改用setUp确保每个测试都有独立的实例,防止状态污染。 - 优先选择
ProviderContainer进行单元测试,减少Widget树带来的额外复杂度。
内容的提问来源于stack exchange,提问作者Bilal Rabbi
相关产品推荐
相关产品推荐

