首页 > 解决方案 > 部分模拟一个类而不影响 PHP 中的私有属性

问题描述

我有一个包含很多方法的类,由于 mysql 和内存中的 sqlite 数据库之间的某些 sql 不兼容,我只需要模拟一个方法。

class OrderService implements OrderServiceContract
{
    protected $deliveryService;

    public function __construct(Delivery $deliveryService) // DI injected object
    {
        ...
        $this->deliveryService = $deliveryService;
        ...
    }

    public function methodNeedstoBeMocked() 
    {
      ....some sql related code...
    }

    public function returnToWarehouse($orderId) 
    {
      DB::transaction(function() use ($orderId) {
         ...
         $this->deliveryService->someOtherMethod($orderId); // problematic external service call 
         ...
      });
    }

}

现在在我的测试中,我根据这个文档链接部分地模拟了这个类,我调用了returnToWarehousefrom 测试,但是它说

错误:在 null 上调用成员函数 returnToWarehouse()。

意味着该属性$deliveryService在模拟中不存在。

我的测试实现如下。

    /**
     * @test
     */
    public function an_order_can_be_returned_to_warehouse()
    {
        ...
        ...
        $this->partialMock(OrderService::class, function ($mock) {
            $mock->shouldReceive('methodNeedstoBeMocked')->andReturn(collect([]));
        });

        $orderService = app(OrderService::class);

        $orderService->markOrderReturnedToWarehouse($order->id); // here is the problem gets triggered.
        ...
        //assertions
    }

这里可能出了什么问题?有什么方法可以缓解这种情况?提前感谢您的帮助。

标签: laravelmockingphpunitmockery

解决方案


这里的问题是 Mockery 的部分测试替身不调用原始构造函数。有关更多信息,请阅读此处的文档。

或者,您可以考虑以不同的方式模拟“有问题的”方法。例如,您可以将该逻辑提取到存储库(因为您提到它正在处理数据库层),然后可以在测试期间对其进行模拟。


推荐阅读