如何使用Mock Cubit实现Flutter Widget测试并解决相关报错
报错原因
- 第一个
Bad state报错是因为你用mocktail的when直接桩MockCubit的state属性无效:MockCubit的state是bloc_test封装的特殊属性,不能直接用普通的mock方式打桩。 - 第二个类型错误是因为删除桩代码后,mock cubit的初始状态默认为null,和你定义的非空
AState类型不匹配。
修正步骤
- 移除全局的
MockDummyCubit实例,改为每个测试用例前单独创建,避免测试用例之间状态污染 - 用
bloc_test提供的whenListen方法控制MockCubit的状态,这个方法可以同时指定初始状态和后续要emit的状态流
修正后的完整测试代码
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:bloc_test/bloc_test.dart'; import 'package:mocktail/mocktail.dart' as mocktail; import 'package:counter/dummy_cubit.dart'; import 'package:counter/main.dart'; class MockDummyCubit extends MockCubit<AState> implements DummyCubit {} class AStateFake extends Fake implements AState {} void main() { setUpAll(() { mocktail.registerFallbackValue(AStateFake()); }); group('Counter viewer', () { late MockDummyCubit dummyCubit; // 每个测试前新建mock实例,避免状态污染 setUp(() { dummyCubit = MockDummyCubit(); }); Widget getTestWidget(int counter) => MultiBlocProvider( providers: [ BlocProvider<DummyCubit>( create: (BuildContext ctx) => dummyCubit, ), ], child: MaterialApp( home: CounterViewer(counter: counter), ), ); testWidgets('初始状态为InitState时显示加载动画', (WidgetTester tester) async { // 指定初始状态为InitState,无后续状态更新 whenListen( dummyCubit, Stream.empty(), initialState: const InitState(), ); await tester.pumpWidget(getTestWidget(1)); expect(find.byType(CircularProgressIndicator), findsOneWidget); }); testWidgets('状态为StateLoaded时显示计数文本', (WidgetTester tester) async { // 指定初始状态为StateLoaded whenListen( dummyCubit, Stream.empty(), initialState: StateLoaded('test'), ); await tester.pumpWidget(getTestWidget(2)); expect(find.text('2'), findsOneWidget); expect(find.byType(CircularProgressIndicator), findsNothing); }); testWidgets('状态切换时UI同步更新', (WidgetTester tester) async { // 指定状态流依次输出Loading、Loaded whenListen( dummyCubit, Stream.fromIterable([const StateLoading(), StateLoaded('test')]), initialState: const InitState(), ); await tester.pumpWidget(getTestWidget(3)); // 初始状态显示加载 expect(find.byType(CircularProgressIndicator), findsOneWidget); // 等待状态流发射完成、UI更新 await tester.pumpAndSettle(); // 最终显示Loaded状态UI expect(find.text('3'), findsOneWidget); }); }); }
控制DummyCubit状态的方法
所有状态控制都通过whenListen方法实现:
initialState参数指定MockCubit的初始状态,对应测试启动时的默认状态- 第二个参数传入
Stream<AState>类型的状态流,流中发射的所有状态都会被MockCubit按顺序emit,触发对应的UI更新
内容的提问来源于stack exchange,提问作者Federico Conte
相关产品推荐
相关产品推荐

