![](/img/trans.png)
[英]Laravel Mockery - Mocking a class with dependencies injected into constructor
[英]Mockery and Laravel constructor injection
我正在使用带有php单元的laravel 5来创建一个laravel包。 我有一个Repository
..
namespace Myname\Myapp\Repositories;
use Myname\Myapp\Models\PersonModel;
class PersonRepository
{
protected $personModel;
public function __construct(PersonModel $personModel)
{
$this->personModel = $personModel;
}
public function testFunction($var)
{
return $this->personModel->find($var);
}
}
..which实现了一个Model
。
namespace Myname\Myapp\Models;
use Illuminate\Database\Eloquent\Model;
class PersonModel extends Model
{
protected $table = 'person';
}
Laravels IoC自动将PersonModel
注入PersonRepository
的构造函数中。
我正在编写单元测试,我想使用mock来模拟PersonModel
模型,因此我在测试期间没有访问数据库。
namespace Myname\Myapptests\unit;
use Mockery;
class PersonRepositoryTest extends \Myname\Myapptests\TestCase
{
/**
* @test
*/
public function it_returns_the_test_find()
{
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
->shouldReceive('find')
->with('var');
$this->app->instance('Myname\Myapp\Models\PersonModel', $mock);
$repo = $this->app->make('Myname\Myapp\Repositories\PersonRepository');
$result = $repo->testFunction('var');
$this->assert...
}
}
当我运行测试时,我收到一个错误
1)Myname \\ Myapptests \\ unit \\ PersonRepositoryTest :: it_returns_the_test_find ErrorException:传递给Myname \\ Myapp \\ Repositories \\ PersonRepository :: __ construct()的参数1必须是Myname \\ Myapp \\ Models \\ PersonModel的实例,给出Mockery \\ CompositeExpectation的实例
从我所读到的,mockery扩展了它正在模拟的类,因此应该没有注入扩展类代替类型提示父类(PersonModel)的问题
显然我错过了一些东西。 其他示例明确地将模拟对象注入到他们正在测试的类中。 Laravels IoC(应该)为我做这件事。 我必须绑定任何东西吗?
我有一种感觉,虽然嘲弄对象没有按我想象的方式创建(扩展PersonModel),否则我认为我不会看到这个错误。
问题是当你创建你的模拟时:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
->shouldReceive('find')
->with('var');
所以这:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
var_dump($mock);
die();
将输出如下内容: Mockery_0_Myname_Myapp_Models_PersonModel
但是这个:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
->shouldReceive('find')
->with('var');
var_dump($mock);
die();
将输出: Mockery\\CompositeExpectation
所以尝试做这样的事情:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel');
$mock->shouldReceive('find')->with('var');
$this->app->instance('Myname\Myapp\Models\PersonModel', $mock);
$repo = $this->app->make('Myname\Myapp\Repositories\PersonRepository');
$result = $repo->testFunction('var');
虽然Fabio给出了一个很好的答案 ,但这里的问题实际上是测试设置。 Mockery的模拟对象确实符合契约 ,并将在方法参数中传递instanceof
测试和类型提示。
原始代码的问题在于被调用的方法链最终返回期望而不是模拟。 我们应该首先创建一个模拟,然后为该模拟添加期望。
要修复它,请更改:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
->shouldReceive('find')
->with('var');
进入:
$mock = Mockery::mock('Myname\Myapp\Models\PersonModel');
$mock->shouldReceive('find')->with('var');
变量$mock
现在将实现PersonModel
。
奖金:
而不是'Myname\\Myapp\\Models\\PersonModel'
,使用PersonModel::class
。 这是一个更友好的IDE,并将在以后重构代码时帮助您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.