我正在用 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/

10-10 16:51