PHP单元测试调度事件

时间:2018-04-15 18:47:06

标签: php unit-testing phpunit

如何测试在函数调用期间调度事件?

public function updateUser() {
    //Do some update stuff

    $event = new UserUpdated($user);

    $event->attach([
        new SendEmailAddressChangeEmail($emailAddress),
        new SendEmailAddressChangeEmail($oldEmailAddress),
    ]);
    $event->dispatch();
}

除了设置电子邮件地址并查看是否发送了电子邮件之外,我如何检查(使用PHP单元)调度员实际上是否正在调度这些事件?我假设我需要创建某种类型的模拟,但我不确定如何为完全不相关的代码创建模拟。

UserUpdated事件代码:

class UserUpdated extends BaseEvent
{

    public $user;

    public function __construct(User $user) {
        $this->user = $user;
    }
}

和相关的SendEmailAddressChanged处理程序代码:

class SendEmailAddressChangeEmail implements Contracts\HandlerInterface
{
    protected $emailAddress;

    public function __construct($emailAddress) {
        $this->emailAddress = $emailAddress;
    }

    public function handle($event) {
        EmailUtils::sendEmailAddressChangeEmail($this->emailAddress, $event->user->userName, $event->user->userID);
    }
}

1 个答案:

答案 0 :(得分:1)

你所获得的updateUser()方法在一个方面做了两件事情,尤其是(单位)测试效果不佳:

  1. 业务逻辑
  2. 对象创建
  3. 从你自己的感觉来看,我认为这也是你问这个问题的原因。通常不直接测试的代码对于设计问题来说也是一个好的金丝雀,因此通常最好用它来解决。

      

    这两点(1.和2.)是过度简化从"两桩" Misko Hevery在他的清洁代码会谈中详细介绍了

         

    enter image description here

         

    例如" The Clean Code Talks - Inheritance,Polymorphism,&测试"从2008年11月起 - https://youtu.be/4F72VULWFvc?t=1328(" Two Piles" @ 22:08)

    使这段代码更具可测试性的一个解决方案是使用依赖注入。这是用户事件的一个工厂(方法),而对象updateUser()的一个工厂(方法)是一个方法。然后,该具体类型可以使用它注入的工厂对象来获得偶数对象。

    简而言之:如果该更新用户对象需要用户更新事件对象,则需要在其构造函数中请求它。

    由于您有时不想事先创建该用户更新事件对象,另一种方法是注入一个知道如何创建该用户更新事件对象的对象,这些对象称为工厂

    然后,测试可以注入一个工厂,该工厂提供一个事件模拟对象,期望它被调度。

    一个好的调度库btw。已经为测试提供了现成的模拟,但这超出了Phpunit的范围。

    如果您还不了解Phpunit的模拟功能,请查看产品的文档: