我正在用 mock 来运行phpunit(没有数据库/夹具),但是在模拟模型时遇到了麻烦。
$customer = Mockery::mock(CustomerModel::class);
echo $customer->id;
产生错误:
BadMethodCallException: Method Mockery_1_models_Customer::hasAttribute() does not exist on this mock object
然后我尝试了:
$customer->shouldReceive('hasAttribute')->andReturn(true);
但是,我再次遇到:
Fatal error: Call to a member function getDb() on a non-object in ..\yiisoft\yii2\db\ActiveRecord.php on line 135
有什么建议么?
最佳答案
我知道您不接受固定答案,但是我也无法弄清楚。我试图解决的问题实际上是在模型中模拟一些方法,以避免创建基础夹具。
所以我最终在Mockery中使用Proxy
模式实现
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
...
}
在此示例中,
getPrice()
模型中的Product
方法从相关表中返回Product
价格。并且我们在这里对其进行了模拟,这样我们就不必用所有相关的模型装置来填充db了。尽管如此,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;
}
这样,原始模型中的所有属性及其对应的值都可以在模拟中使用。
关于unit-testing - Yii2 ActiveRecord与Mockery mock ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31205770/