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

如何正确测试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:15:34