1

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

4

3 回答 3

0

我找不到如何获得成功的模拟,所以这是一个解决方法。我更担心代码覆盖率,而不是实际测试这个“保存”异常。无论如何,我只是用下面的注释包装了实际代码,这告诉 phpunit 在分析代码覆盖率时忽略它:

// @codeCoverageIgnoreStart
[code goes here]
// @codeCoverageIgnoreEnd

我不想捏造它,但代码非常简单,所以我真的不担心。

于 2013-04-25T15:05:24.463 回答
0

那么你要模拟的模型也是被测组件吗?我会尝试改变这一点。

我要测试的是在尝试使用 $model->save() 更新现有模型上的数据时捕获的异常。

不确定我是否理解正确(测试代码会有所帮助),但看起来模拟资源模型通常是一个好主意。这也使您可以独立于数据库运行测试。

你的出发点:

$resourceModelMock = $this->getResourceModelMock('test/model');
$resourceModelMock->expects($this->once())
    ->method('save')
    ->will($this->throwException(...));
$this->replaceByMock('resource_model', 'test/model', $resourceModelMock);

请注意,我从字面上理解了您的“异常被捕获”,并假设资源模型将引发您的模型应该捕获的异常。但是我怀疑你的意思是“扔”。在这种情况下,你的模拟应该返回一些有效的东西。

于 2013-03-22T17:42:25.657 回答
0

您可以为集合资源注册一个额外的 Mock。并且每个集合项都会成为一个 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);
}

}

于 2014-12-05T15:24:45.523 回答