【问题标题】:Mocking new object creation with PhpSpec in Laravel在 Laravel 中使用 PhpSpec 模拟新对象的创建
【发布时间】:2017-10-03 11:16:07
【问题描述】:

我有一个名为 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.

【问题讨论】:

    标签: php laravel phpspec


    【解决方案1】:

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

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

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

    使一切按预期工作。

    编辑

    或者更好的是,完全模拟服务容器:

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

    并在您的letGo() 函数中调用\Mockery::close()。 该类无法接收具体的类实现,您实际上测试了该类是否首先向服务容器发出了解析请求。

    【讨论】:

    • 或者更好的是,创建一个工厂并将其用作依赖项并模拟工厂;)
    猜你喜欢
    • 2023-02-26
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多