如何正确测试StateNotifier对Stream事件的响应逻辑
我的实现配置
我编写了一个StateNotifier,其状态类由@freezed注解生成:
@freezed class MyFreezedState with _$MyFreezedState{ const factory MyFreezedState({ required AsyncValue<int> asyncFreezedStateInt, }) = MyFreezedState; }
class MyStateNotifier extends StateNotifier<MyFreezedState>{ const MyStateNotifier(MyFreezedState state) : super(state); }
我需要在StateNotifier内部监听Stream事件,根据事件结果更新对应状态,最终完整实现代码如下:
final myStateNotifierProvider = Provider<MyStateNotifier, MyFreezedState>((ref) { final intStream = ref.watch(myIntStreamProvider); return MyStateNotifier( MyFreezedState( asyncFreezedStateInt: AsyncValue.loading(), ), asyncIntStreamValue : intStream ); }); class MyStateNotifier extends StateNotifier<MyFreezedState>{ MyStateNotifier ( MyFreezedState state, { required this.asyncIntStreamValue, }) : super(state) { reactToIntStreamChanges(); } final AsyncValue<int> asyncIntStreamValue; void reactToIntStreamChanges(){ asyncIntStreamValue.when( data: (intData) { state = state.copyWith(asyncFreezedStateInt : AsyncValue.data(intData); }, error: (err, stk) { state = state.copyWith(asyncFreezedStateInt : AsyncValue.error(err,stk); }, loading () { state = state.copyWith(asyncFreezedStateInt : AsyncValue.loading(); } } }
上述代码在实际运行时功能完全符合预期。
存在的问题
我目前不知道如何正确测试StateNotifier对Stream事件的响应逻辑,当前测试环境配置如下:
void main() { late ProviderContainer container; late MockIntService mockIntService; setUp((){ mockIntService = MockIntService(); container = ProviderContainer( overrides: [myIntServiceProvider.overrideWithValue(mockIntService)], ); when(() => mockIntService.myIntStream).thenAnswer((invocation) { return Stream<int>.fromIterable([1]); }); })
已尝试的解决方案
无效方案
如下测试用例执行失败,读取到的状态值始终为AsyncValue.loading():
// 该测试执行失败,获取到的状态值仍为AsyncValue.loading() test('should set the states value if stream emits value',(){ final stateValue = container.read(myStateNotifierProvider).asyncFreezedStateInt; expect(stateValue, AsyncValue.data(1)); });
可运行但不规范的临时方案
查阅相关资料后我实现了如下可通过测试的方案,但我认为该实现属于hack性质的取巧写法,应当存在更优雅合理的实现方式:
// 该测试可通过,但我认为这不是合理的实现方案 test('should set the states value if stream emits value',(){ fakeAsync((async){ container.read(myStateNotifierProvider); async.elapse(const Duration(milliseconds:100); final stateValue = container.read(myStateControllerProvider).asyncFreezedStateInt; expect(stateValue, AsyncValue.data(1)); }); }); }
补充说明
Stream来源的服务类精简实现代码如下:
final myIntStreamProvider = StreamProvider((ref) { return ref.read(intServiceProvider).intStream; }); final intServiceProvider = Provider<BaseTemplateService>((ref) { return IntService(); }); class IntService { Stream<Int> get intStream => firestore .collection("intValues") .snapshots(); }
欢迎大家提供相关建议,感谢!
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

