我尝试使用Mockery lib模拟我的服务方法。如果我从测试的上下文中调用该方法,它将起作用。但是,如果我从另一个方法调用它(例如,它从另一个经过测试的方法调用)-它从实现中返回原始数据,而不是从模拟返回。我做错了什么? 示例如下。
我添加了合同,因为我的实际实现使用它。我认为该问题与接口无关。
app / Contracts / TransactionsServiceContract.php
namespace App\Contracts;
interface TransactionsServiceContract
{
public function getAllRequests(): array;
public function getRequests(array $necessaryFields): array;
}
app / Services / TransactionsService.php
namespace App\Services;
use App\Contracts\TransactionsServiceContract;
class TransactionsService implements TransactionsServiceContract
{
public function getAllRequests(): array
{
return [
'foo' => [
'metric' => 'foo',
],
'bar' => [
'metric' => 'bar',
],
'another' => [
'metric' => [
// Some fields
],
],
];
}
public function getRequests(array $necessaryFields): array
{
// dd($this->getAllRequests()); // -> for the test context it returns original value (above's one)
return collect($this->getAllRequests())->only($necessaryFields)
->map(function (array $metric) {
return $metric['formula'];
})
->toArray();
}
}
tests / Feature / TransactionsServiceTest.php
namespace Tests\Feature;
use App\Contracts\TransactionsServiceContract;
use Tests\TestCase;
class TransactionsServiceTest extends TestCase
{
/** @var TransactionsServiceContract */
private $_transactionsService;
public function setUp()
{
parent::setUp();
$requests = [
'test1' => [
'metric' => 'test 1',
],
'test2' => [
'metric' => 'test 2',
],
];
$this->_transactionsService = \Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
$this->_transactionsService->shouldReceive('getAllRequests')->andReturn($requests);
}
public function testInternalCall()
{
$directCall = $this->_transactionsService->getAllRequests(); // returns array "requests" from the setUp method
dump($directCall);
$internalCall = $this->_transactionsService->getRequests(['test1']);
dd($internalCall); // if we call getAllRequests into getRequests, but not from test's context, we get original array from real implementation, but not test's mock
}
}
libs / frameworks的版本:
感谢您的关注。新年快乐! :)
答案 0 :(得分:0)
当您在\Mockery::mock(app()->make(TransactionsServiceContract::class))->makePartial();
方法中调用setUp
时,并没有真正替换应用容器中现有的实现。 Laravel的容器为您提供了bind方法(the documentation for that)。此外,您不会用模拟代替接口,因为接口对每个定义都不会做任何事情。
因此,实际上您会执行以下操作:
app()->bind('\App\TransactionsService', $mockedTransactionService);
请注意,只有在您的代码通过注入或解析而不是通过调用
new TransactionService
来获取TransactionService实例的情况下,此方法才有效。