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

当AsyncData为List<Object>时,如何对控制器初始状态做单元测试?

问题排查:Riverpod控制器初始状态测试提示“无匹配调用”

我在测试一个Riverpod控制器的初始状态时,测试一直失败,提示“无匹配调用”。但用相同逻辑测试其他控制器时完全正常——唯一区别是那些控制器的AsyncValue类型为void,默认值是null,而当前控制器的AsyncValue是List类型,默认值为空列表。

测试代码

test('initial state is AsyncValue.data', () async {
  // assert
  var service = MockSpaceService();
  var container = makeProviderContainer(service);
  var listener = Listener<AsyncValue<List<Space>>>();
  container.listen(spaceListControllerProvider, listener.call,
      fireImmediately: true);
  verify(
    () => listener(null, const AsyncData<List<Space>>([])),
  );
  verifyNoMoreInteractions(listener);
});

控制器代码

@riverpod
class SpaceListController extends _$SpaceListController {
  @override
  FutureOr<List<Space>> build() => [];
}

错误信息

No matching calls. All calls: Listener<AsyncValue<List<Space>>>.call(null, AsyncData<List<Space>>(value: []))
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
package:matcher                                                          fail
package:mocktail/src/mocktail.dart 728:7                                 _VerifyCall._checkWith
package:mocktail/src/mocktail.dart 519:18                                _makeVerify.<fn>
test\features\spaces\presentation\space_list_controller_test.dart 58:13  main.<fn>.<fn>

问题原因与解决办法

问题出在常量空列表的匹配上:测试里用了const AsyncData<List<Space>>([]),但控制器build方法返回的是普通空列表[],两者不是同一个对象,Mocktail严格的同一性检查导致匹配失败。

有三种解决方式:

  • 方式一:修改测试代码,把常量空列表改成普通空列表
    verify(
      () => listener(null, AsyncData<List<Space>>([])),
    );
    
  • 方式二:修改控制器代码,返回常量空列表
    @override
    FutureOr<List<Space>> build() => const [];
    
  • 方式三:用Mocktail的equals()匹配器做宽松匹配,不检查对象同一性只看内容
    verify(
      () => listener(null, AsyncData(equals([]))),
    );
    

内容的提问来源于stack exchange,提问作者steve

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:19:55