当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
相关产品推荐
相关产品推荐

