事件订阅者单元测试运行结果不符合预期如何排查
问题根因
测试不通过本质是单元测试里常见的实例引用不匹配错误:测试方法内手动创建的$user对象,和事件订阅者运行时实际操作的User对象根本不是同一个实例,二者没有任何关联,你在测试侧创建的对象属性从头到尾没被修改过,断言自然失败。
具体错误点:
- 你在测试里手动
new User()造了一个用户对象、设置了邮箱和订阅状态,但订阅者onUnsubscribedListReceived方法的内部逻辑,一定是先通过userRepository按邮箱查询匹配的用户,再修改查询到的用户的订阅状态,最后调用save持久化。整个流程里,订阅者根本拿不到你在测试里手动new的这个$user,自然不会修改它的属性。 - 你给
userRepositorymock配置的->with($user)save参数断言本身就不成立:订阅者传给save的是它自己从仓储查出来的用户实例,不是你测试里造的这个。如果测试跑到最后才报属性断言失败、没报参数匹配错误,说明你根本没给仓储的查询方法(比如findOneByEmail)配置mock返回值,订阅者查不到对应邮箱的用户,甚至根本没走到修改属性、调用save的分支,你测试里的$user从创建到断言全程没被改动过,值当然还是true。
修复方式
正确配置mock的方法返回值,保证订阅者操作的就是你在测试里创建的用户实例,参考代码如下:
// 创建测试用的用户实例,后续要让仓储mock把这个实例返回给订阅者 $user = new User(); $user->email = self::EMAIL; $user->subscribed_to_mailing_list = true; // 先mock仓储的查询方法:指定查询对应邮箱时,返回上面创建的$user实例 $this->userRepository->expects($this->once()) ->method('findOneByEmail') ->with(self::EMAIL) ->willReturn($user); // 再配置save方法的断言,用回调校验传入的用户状态符合预期 $this->userRepository->expects($this->once()) ->method('save') ->with($this->callback(function (User $savedUser) use ($user) { return $savedUser === $user && $savedUser->subscribed_to_mailing_list === false; })); // 触发事件订阅逻辑 $event = new UnsubscribedEmailsEvent([self::EMAIL]); $this->subscriber->onUnsubscribedListReceived($event); // 此时断言才有效:因为$user就是订阅者实际修改的实例 $this->assertFalse($user->subscribed_to_mailing_list);
如果你的仓储查询方法名不是
findOneByEmail,替换成代码里实际调用的方法名即可,核心逻辑是必须让mock仓储把你测试里创建的$user实例返回给订阅者,二者操作同一个对象时断言才会生效。
内容的提问来源于stack exchange,提问作者Serghei Leonenco
相关产品推荐
相关产品推荐

