EcomDev_PHPUnit模拟集合中的Magento模型

时间:2013-03-22 15:40:07

标签: magento phpunit

我已经成功使用了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()更新现有模型上的数据时遇到的异常。

3 个答案:

答案 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);
}

}