Yii2 ActiveRecord与Mockery嘲笑

Mār*_*dis 6 activerecord phpunit unit-testing mockery yii2

我正在用嘲弄运行phpunit(没有DB/fixtures),但是我在模拟模型时遇到了麻烦.

$customer = Mockery::mock(CustomerModel::class);
echo $customer->id;
Run Code Online (Sandbox Code Playgroud)

产生错误:

BadMethodCallException: Method Mockery_1_models_Customer::hasAttribute() does not exist on this mock object

然后我尝试了:

$customer->shouldReceive('hasAttribute')->andReturn(true);
Run Code Online (Sandbox Code Playgroud)

但是,我再次参与:

Fatal error: Call to a member function getDb() on a non-object in ..\yiisoft\yii2\db\ActiveRecord.php on line 135

有什么建议?

pau*_*lus 4

我知道您不接受固定答案,但我也无法弄清楚。我试图解决的问题实际上是模拟模型中的某些方法,以避免创建底层装置。

所以我最终Proxy在 Mockery 中使用了模式实现

private $_product;
public function testMe() 
{
   // Here we use fixtured instance of Product model to build a Proxy
   $this->_product = \Mockery::mock($this->product('product1')); 
   // somehow model attributes are inaccessible via proxy, but we can set them directly as a Proxy property
   $this->_product->id = 1; 
   $this->_product->shouldReceive('getPrice')->andReturn(1000);
   // assertions below
   ...
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,getPrice()方法来自Product返回Product相关表中的价格。我们在这里模拟它,这样我们就不必用所有相关的模型装置填充数据库。尽管如此,Product它本身仍然是一个固定装置。

也许不是最好的解决方案,但设法节省了我一些 CPU 时间,同时保持单元测试解耦。

文档在这里 http://docs.mockery.io/en/latest/reference/partial_mocks.html

更新

我还做了一个小助手来解决属性代理问题

/**
 * @param \yii\base\Model $model
 * @return \Mockery\MockInterface
 */
private function setupMock($model)
{
    $mock = \Mockery::mock($model);
    foreach ($model->getAttributes() as $key => $value) {
        $mock->$key = $value;
    }
    return $mock;
}
Run Code Online (Sandbox Code Playgroud)

这样,原始模型中的所有属性及其相应的值都可以在模拟中使用。