在Laravel中使用PhpSpec模拟新对象创建

时间:2017-10-03 11:16:07

标签: php laravel phpspec

我有一个名为Campaign的班级,负责在外部API中预订单个广告系列。我有EntryBooking课程负责准备条目并使用Campaign课程进行预订。在某些情况下,我可能希望创建多个广告系列,因此对于每个广告系列,我想创建一个新的Campaign对象,并在其上调用book()方法。 (每个广告系列都有自己的Campaign对象)

我遇到的问题是我想对EntryBooking类进行单元测试,我想模拟Campaign个对象。

我正在使用BenConstable/phpspec-laravel包,因此我可以访问我的规格中的外墙。

我想这样做:

# EntryBookingSpec.php
function it_should_book_campaigns_for_entry(Entry $entry, Campaign $campaignMock)
{
    $campaignMock->book()->shouldBeCalled();
    App::instance(Campaign::class, $campaignMock);

    $this->bookForEntry($entry);
}

-

# EntryBooking.php
class EntryBooking
{
    public function bookForEntry(Entry $entry): void
    {
        $campaign = App::make(Campaign::class);
        // do the processing and set values for $campaign
        $campaign->book();
    }
}

我正在尝试使用App::instance(),因为在实时环境中,App::make()每次调用时都会创建一个新实例,但在测试时我希望它返回同一个对象,我可以就此发表断言。

问题是预测失败。即使我打电话给$campaignMock->book()->shouldBeCalled();,在测试课程中我打电话给$campaign->book()我仍然得到:

some predictions failed:
    Double\vendor\package\Campaign\P1:
      No calls have been made that match:
        Double\vendor\package\Campaign\P1->book()
      but expected at least one.

1 个答案:

答案 0 :(得分:0)

事实证明,当您使用构造函数使用依赖注入时,PhpSpec将自动从MethodProphecy创建一个模拟对象,但是如果您希望服务容器返回模拟对象,则需要在其上传递一个包装对象拥有。 所以改变以下

App::instance(Campaign::class, $campaignMock);

App::instance(Campaign::class, $campaignMock->getWrappedObject());

使一切按预期工作。

修改

甚至更好,完全模拟服务容器:

App::shouldReceive('make')
    ->with(Campaign::class)
    ->andReturn($campaignMock->getWrappedObject());

\Mockery::close()函数中调用letGo()。 该类无法接收具体的类实现,并且您实际测试该类是否首先解析了对Service Container的请求。