Flutter中用Mocktail结合bloc_test验证另一个Bloc状态变更
问题描述
我想用bloc_test验证:当给BlocA添加SignIn事件时,BlocB的User状态是否被更新为指定值。场景细节:
- BlocA包含
SignIn事件 - BlocB的状态包含User字段,可通过
UserChanged事件更新
我的实现代码如下:
act: (blocA) { blocA.add(SignIn()); }, verify: (bloc) { verify(() => BlocB.add( UserChanged( user: any( named: "user", that: isA<User>().having( (user) => user.email, "email", "test@test.co1m", ), ), ), )).called(1); },
运行后触发错误:
Invalid argument(s): An ArgumentMatcher was declared as named user, but was not passed as an argument named user. BAD: when(() => obj.fn(any(named: "a"))) GOOD: when(() => obj.fn(a: any(named: "a")))
补充:如果不验证UserChanged事件的参数,测试可以正常通过,代码示例:
act: (blocA) { blocA.add(SignIn()); }, verify: (bloc) { verify(() => BlocB.add(any<UserChanged>())).called(1); },
解决方法
你遇到的错误核心是:错误地将any()的named参数绑定到了Bloc.add方法上,但Bloc.add只有一个位置参数(事件对象),不存在名为user的命名参数。下面是两种正确的实现方式:
方式一:用argThat匹配事件属性
直接针对BlocB.add接收的事件对象做匹配,验证其中的user属性是否符合预期:
verify(() => BlocB.add( argThat( isA<UserChanged>().having( (event) => event.user.email, '用户邮箱', 'test@test.co1m', ), ), )).called(1);
方式二:捕获事件后直接断言
先捕获BlocB接收到的事件,再逐个断言事件类型和属性,写法更直观:
// 捕获BlocB接收到的所有事件 final capturedEvents = verify(() => BlocB.add(captureAny())).captured; // 断言事件类型为UserChanged expect(capturedEvents.first, isA<UserChanged>()); // 取出事件并验证user的邮箱 final targetEvent = capturedEvents.first as UserChanged; expect(targetEvent.user.email, 'test@test.co1m');
错误原因回顾
你之前的代码里,any(named: "user")是在匹配BlocB.add的参数,但add方法的参数是位置传递的事件对象,根本没有user这个命名参数,所以触发了参数匹配错误。而使用any<UserChanged>()时,只是匹配事件的类型,没有指定错误的命名参数,所以测试能通过。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

