#php #unit-testing #magento #mocking
#php #модульное тестирование #magento #издевательство
Вопрос:
Я пишу несколько тестов для модуля Magento, используя расширение Ивана Чепурного, и у меня возникают проблемы с использованием фиктивных объектов.
Вот класс:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
public function __construct()
{
$this->_salesCollection = Mage::getModel('module/classA')->getCollection()
->addFieldToFilter('id', $this->_getId());
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_salesCollection->count();
}
}
Метод, который я пытаюсь протестировать, — это getSalesTotalNumber().
И вот тест:
<?php
class Namespace_Module_Test_Block_Class extends EcomDev_PHPUnit_Test_Case
{
private $_mock;
public function setUp()
{
$this->_mock = $this->getMock('Namespace_Module_Block_Class',
array('_getId')
);
$this->_mock->expects($this->any())
->method('_getId')
->will($this->returnValue(1024));
parent::setUp();
}
/**
* @test
* @loadFixture
* @loadExpectation
*/
public function testSalesTotalNumber()
{
$actual = $this->_mock->getSalesTotalValue();
$expected = $this->_getExpectations()->getSalesTotalNumber();
$this->assertEquals($expected, $actual);
}
}
Как вы можете видеть, что я хочу сделать, это перезаписать метод _getId() так, чтобы он возвращал идентификатор, соответствующий идентификатору в fixture, и таким образом загрузить коллекцию. Но это не работает :-(.
В моем тесте, если я выполняю эхо $this->_mock->_getId()
, он возвращает правильный идентификатор (1024). Но в __construct()
моем классе $this->_getId()
возвращается значение null, которое является ожидаемым значением во время тестирования (я имею в виду, что во время тестирования нет сеанса, поэтому он не может получить идентификатор объекта, поскольку я сохраняю его в переменной сеанса). Таким образом, в моем тестовом примере метод _getId() не высмеивается.
Любая помощь будет высоко оценена.
Комментарии:
1. Хорошо, проблема была не в макете, а в структуре класса. Я удалил
__construct()
и переместил его содержимое в частный метод, который возвращает объект коллекции: мой тест пройден, и у меня есть лучший, несвязанный класс. Мне нравится TDD 😀2. Вы могли бы подумать о том, чтобы ответить на свой собственный вопрос, чтобы другим было легче его найти. Это вполне разрешено. На данный момент он классифицирован как «без ответа»
3. Это правда, Питер, держи 🙂
4. Эй, Дэвид, почему ты не используешь методы $this->getModelMock() и replaceByMock()?
5. @Ivan, в основном потому, что я не знал, что они существуют :), я рассмотрю это для моего следующего макета. спасибо за проявленный интерес
Ответ №1:
Итак, моя проблема была не в макете / тестировании, а в классе.
Я переместил содержимое __construct()
в защищенный метод, который возвращает объект коллекции. Вот как теперь выглядит мой класс:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
protected function _getAffiliateSales()
{
if (is_null($this->_salesCollection)) {
$affiliateId = $this->_getId();
$this->_salesCollection = Mage::getModel('module/classA')
->addFieldToFilter('id', $affiliateId);
}
return $this->_salesCollection;
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_getAffiliateSales()->count();
}
}