部分模拟 class 而不影响 PHP 中的私有属性
partially mocking a class without affecting the private properties in PHP
我有一个 class 有很多方法,由于 mysql 和内存中 sql 之间的一些 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
...
});
}
}
现在在我的测试中,我根据 this doc link 部分模拟了这个 class,然后我从测试中调用了 returnToWarehouse
,但它说
Error : Call to a member function returnToWarehouse() on null.
意思是 属性 $deliveryService
在 mock 中不存在。
我的测试实现如下
/**
* @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
}
这里可能出了什么问题?有哪些方法可以减轻这种情况?提前感谢您的帮助。
通常,当我必须模拟一些第三方服务时,我会设置一个像这样的模拟。
这样您可以轻松设置您的 DI 服务
<?php
if (app()->environment('testing')) {
$this->app->bind(Delivery::class, static function () {
$service = \Mockery::mock(Delivery::class);
$service->shouldReceive('someOtherMethod')->andReturn([]);
return $service;
});
}
这里的问题是来自 Mockery 的部分测试替身不调用原始构造函数。有关详细信息,请阅读文档 here.
或者,您可以考虑以不同方式模拟 "problematic" 方法。例如,您可以将该逻辑提取到 存储库 (因为您提到它正在处理数据库层),然后可以在测试期间对其进行模拟。
我有一个 class 有很多方法,由于 mysql 和内存中 sql 之间的一些 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
...
});
}
}
现在在我的测试中,我根据 this doc link 部分模拟了这个 class,然后我从测试中调用了 returnToWarehouse
,但它说
Error : Call to a member function returnToWarehouse() on null.
意思是 属性 $deliveryService
在 mock 中不存在。
我的测试实现如下
/**
* @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
}
这里可能出了什么问题?有哪些方法可以减轻这种情况?提前感谢您的帮助。
通常,当我必须模拟一些第三方服务时,我会设置一个像这样的模拟。
这样您可以轻松设置您的 DI 服务
<?php
if (app()->environment('testing')) {
$this->app->bind(Delivery::class, static function () {
$service = \Mockery::mock(Delivery::class);
$service->shouldReceive('someOtherMethod')->andReturn([]);
return $service;
});
}
这里的问题是来自 Mockery 的部分测试替身不调用原始构造函数。有关详细信息,请阅读文档 here.
或者,您可以考虑以不同方式模拟 "problematic" 方法。例如,您可以将该逻辑提取到 存储库 (因为您提到它正在处理数据库层),然后可以在测试期间对其进行模拟。