如何测试addPostFrameCallback回调内emit状态的bloc/cubit
方案1:在testWidgets中手动监听Cubit状态流(推荐,更贴合真实业务场景)
blocTest的状态校验本质是监听Cubit的stream属性收集emit的状态,你完全可以在testWidgets环境中自己实现这个逻辑,同时借助tester的帧调度能力触发addPostFrameCallback:
testWidgets( 'constructor emits chatIsLoading: false after scroll to bottom completes', (WidgetTester tester) async { // 初始化ScrollController并挂载到真实ListView,模拟业务场景的滚动环境 final scrollController = ScrollController(); await tester.pumpWidget( MaterialApp( home: Scaffold( body: ListView( controller: scrollController, // 生成足够多的列表项模拟真实聊天列表的滚动高度 children: List.generate(100, (index) => Text('消息$index')).toList(), ), ), ), ); final cubit = ChatCubit(scrollController); // 收集所有emit的状态 final emittedStates = <ChatState>[]; final streamSub = cubit.stream.listen(emittedStates.add); // 触发帧调度,等待所有postFrameCallback、递归滚动逻辑执行完成 await tester.pumpAndSettle(); // 校验状态是否符合预期 expect(emittedStates, [ChatState(chatIsLoading: false)]); // 测试资源释放 await streamSub.cancel(); cubit.close(); scrollController.dispose(); }, );
方案2:在blocTest中手动调度帧(适合单元测试,运行速度更快)
如果不需要真实的页面渲染,也可以在blocTest中初始化WidgetBinding,手动触发帧回调执行你的逻辑:
import 'package:mockito/mockito.dart'; blocTest<ChatCubit, ChatState>( 'constructor emits chatIsLoading: false after frame callback runs', // 初始化WidgetBinding获取帧调度能力 setUp: () => WidgetsFlutterBinding.ensureInitialized(), build: () { // 用Mockito打桩ScrollController及其依赖,避免依赖真实渲染环境 final mockScrollController = MockScrollController(); when(mockScrollController.hasClients).thenReturn(true); when(mockScrollController.position).thenReturn( ScrollPosition.withSingleContext( physics: const AlwaysScrollableScrollPhysics(), context: MockScrollContext(), initialPixels: 0, keepScrollOffset: true, oldPosition: null, ), ); when(mockScrollController.jumpTo(any)).thenReturn(null); return ChatCubit(mockScrollController); }, act: (cubit) async { // 手动触发帧执行postFrameCallback WidgetsBinding.instance.handleBeginFrame(Duration.zero); WidgetsBinding.instance.handleDrawFrame(); // 等待递归滚动逻辑执行完成 await Future.doWhile(() => Future.delayed(Duration.zero, () => cubit.state.chatIsLoading)); }, expect: () => [ChatState(chatIsLoading: false)], );
内容的提问来源于stack exchange,提问作者Vega180
相关产品推荐
相关产品推荐

