我已经成功使用了getModelMock()和replaceByMock('model',$ model_path,$ mock)。今天我试图重用这个代码来覆盖“保存”,但它没有用。经过一番挖掘后,我现在看到了为什么模型没有被嘲笑的区别。
成功使用模拟时,我的代码以新模型开始:
$model = Mage::getModel('test/model');
$model->setData('field', 'value');
$model->save(); //this gets mocked
未被模拟的代码我正在使用集合加载记录。简化为:
$model = Mage::getModel('test/model')->getCollection()->getFirstItem();
$model->setData('field', 'value');
$model->save(); //this does NOT get mocked
在这两种情况下,我都使用以下代码来模拟模型:
$mock = $this->getModelMock('test/model', array('save'));
$mock->expects($this->once())
->method('save')
->will($this->returnCallBack(function(){throw new Exception('Mock error');})
);
$this->replaceByMock('model', 'test/model', $mock);
我还尝试使用以下资源模型:
$mock = $this->getResourceModelMock('test/model', array('save'));
$mock->expects($this->once())
->method('save')
->will($this->returnCallBack(function(){throw new Exception('Mock error');})
);
$this->replaceByMock('resource_model', 'test/model', $mock);
在单步执行代码后,我想也许我只需要模拟资源模型。这没有用,也没有模仿模型和资源模型。我尝试测试的是尝试使用$ model-> save()更新现有模型上的数据时遇到的异常。
答案 0 :(得分:0)
那么你想要模拟的模型也是被测试的组件?我会尝试改变它。
我尝试测试的是尝试使用$ model-> save()更新现有模型上的数据时遇到的异常。
不确定我是否理解正确(测试代码会有所帮助)但看起来模拟资源模型通常是一个好主意。这也使您可以独立于数据库运行测试。
您的出发点:
$resourceModelMock = $this->getResourceModelMock('test/model');
$resourceModelMock->expects($this->once())
->method('save')
->will($this->throwException(...));
$this->replaceByMock('resource_model', 'test/model', $resourceModelMock);
请注意,我从字面上理解了“异常被捕获”并假设资源模型会抛出一个异常,模型应该 catch 。但是我怀疑你真的是“被抛出”。在这种情况下,你的模拟应该返回一些有效的东西。
答案 1 :(得分:0)
我找不到如何获得成功的模拟,所以这是一个解决方法。我更担心代码覆盖率而不是实际测试此“保存”异常。无论如何,我只是将实际代码包含在下面的注释中,这些注释告诉phpunit在分析代码覆盖时忽略它:
// @codeCoverageIgnoreStart
[code goes here]
// @codeCoverageIgnoreEnd
我宁愿不捏造它,但代码非常简单,所以我真的不担心。
答案 2 :(得分:0)
您可以为收集资源注册一个额外的模拟。 每个集合项都将成为Mock对象。
这是一个小例子:
class YourCompany_YourModule_Test_Model_CatalogProduct extends EcomDev_PHPUnit_Test_Case {
/**
* Create product model mock and replace `getCollection` method with callback
*
* @return $this
* @throws PHPUnit_Framework_Exception
*/
protected function _registerProductStub()
{
$productModelMock = $this->getModelMock('catalog/product', array('getPrice', 'getCollection'));
$productModelMock->expects($this->any())->method('getPrice')->will($this->returnCallback(array($this, 'callbackGetTestValue')));
$productModelMock->expects($this->any())->method('getCollection')->will($this->returnCallback(array($this, 'callbackGetCollection')));
$this->replaceByMock('model', 'catalog/product', $productModelMock);
return $this;
}
/**
* Create a product collection resource model with Mock and replace `getNewEmptyItem` method with callback
*
* @return $this
* @throws PHPUnit_Framework_Exception
*/
protected function _registerProductCollectionStub()
{
$productModelMockModelCollectionMock = $this->getResourceModelMock('catalog/product_collection', array('getNewEmptyItem'));
$productModelMockModelCollectionMock->expects($this->any())->method('getNewEmptyItem')->will($this->returnCallback(array($this, 'callbackGetNewEmptyItem')));
$this->replaceByMock('resource_model', 'catalog/product_collection', $productModelMockModelCollectionMock);
return $this;
}
/**
* Magento EAV checks that class of object is the same with predefined $this->_itemObjectClass
* So we need to replace it too.
*/
public function callbackGetCollection()
{
$model = Mage::getModel('catalog/product');
$collection = $model->getResourceCollection();
$collection->setItemObjectClass(get_class($model));
$collection->getSelect()->limit(10);
return $collection;
}
/**
* We change a default functionality and
* new empty object calling will return a mock object
* in place of straight creating object trough `new ClassName`.
* Magento will automatically add data to this object from your fixture or database.
*
* @return Mage_Catalog_Model_Product
*/
public function callbackGetNewEmptyItem()
{
return Mage::getModel('catalog/product');
}
public function callbackGetTestValue()
{
return 99.99;
}
/**
* @test
*/
public function test_productModelIsMock()
{
$this->_registerProductStub()
->_registerProductCollectionStub();
$mockedProduct = Mage::getModel('catalog/product');
$mockedProductFromCollection = Mage::getModel('catalog/product')->getCollection()->getFirstItem();
$this->assertEquals(get_class($mockedProduct), get_class($mockedProductFromCollection));
$this->assertEquals($mockedProduct->getPrice(), $mockedProductFromCollection->getPrice());
$this->assertEquals($mockedProduct->getPrice(), 99.99);
}
}