2

我正在使用 PHPUnit 进行测试,但我的测试在函数上失败了。但我不知道为什么。我要模拟的功能:

public function subscribe($email)
{
    $message = new SubscribeMessage();
    $message->setEmailaddress($email);
    $message->setLocale(Locale::getDefault());
    $this->getAmqpProducer()->publish($message, 'newsletter-subscribe');
    return true;
}

和我的单元测试:

public function testSubscribeSendsAmqpMessage()
{
    $email = 'email@email.nl';
    $locale = 'nl';

    $this->amqpProducerMock
        ->shouldReceive('publish')
        ->once()
        ->with(

            \Mockery::on(
                function ($message, $routingkey) use (&$publishedMessage) {
                    $publishedMessage = $message;
                    return $routingkey == 'newsletter-subscribe';
                }
            )
        );

    $this->service->subscribe($email, $locale);
}

但测试说:

Mockery\Exception\NoMatchingExpectationException : No matching handler found for AcsiRabbitMq\Producer\Producer::publish(AcsiNewsletter\RabbitMq\Message\SubscribeMessage, "newsletter-subscribe"). Either the method was unexpected or its arguments matched no expected argument list for this method

如何修复我的单元测试?或者我该如何重构我的测试?

4

1 回答 1

1

您模拟订阅,而不是内部发布。当您运行测试并调用 ->subscribe 时,它​​将尝试执行类中的代码。因此,它将尝试运行 subscribe() 方法,您似乎对您的 Mock 有一个奇怪的引用。

通常,您的测试将模拟订阅,因此您可以为断言测试返回一个值,该值是硬编码的。

您似乎试图模拟常规代码中的 GetAmqpProducer() 对象。您需要能够将要使用的模拟对象传递给您的类,或者能够分配它。

简化示例:

class Email
{
    private $MsgObject;

    // Constructor Injection
    public __construct(SubscribeMessage $MessageObject)
    {
        $this->MsgObject = $MessageObject;
        ...
    }

    // Setter Injection
    public function SetSubscribeMessage(Subscribe $MessageObject)
    {
        $this->MsgObject = $MessageObject;
    }   

    public function setEmailaddress($email)
    {
        $this->MsgObject->emailAddress = $email;
        ...
    }

    public function setLocale($Locale)
    {
        $this->MsgObject->Locale = $Locale;
        ...
    }

    ...

}

上面的类示例有太多内部对象和依赖项需要进行测试,因为测试实际上会调用它们。您将使用依赖注入来传递具有已知状态的对象,并让它们正确返回。

请注意,我没有展示如何在 Mockery 中执行此操作,因为我不使用它,但是这个简单的示例应该可以帮助您理解我想要表达的内容。

所以一个简单的测试可能看起来像:

public function testSubscribeMessage()
{
    $email = 'email@email.nl';
    $this->Mock(
        ->shouldReceive('setEmailAddress')
        ->once()
        ->will_return($email)
        );

    $SubscribeMessage = new SubscribeMessage($this->Mock);
    $SetEmail = $SubscribeMessage->setEmailAddress($email);
    $this->assertEquals($email, $SetEmail);
}
于 2013-08-26T15:51:24.280 回答