Это продолжение предыдущего вопроса, который у меня был: Как лучше отделить слой данных и ограничить объем моих модульных тестов?
Я прочитал о Zend и DI / IoC и предложил следующие изменения в моем коде:
Модуль Bootstrap
class Api_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initAllowedMethods()
{
$front = Zend_Controller_Front::getInstance();
$front->setParam('api_allowedMethods', array('POST'));
}
protected function _initResourceLoader()
{
$resourceLoader = $this->getResourceLoader();
$resourceLoader->addResourceType('actionhelper', 'controllers/helpers', 'Controller_Action_Helper');
}
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addHelper(new Api_Controller_Action_Helper_Model());
}
}
Помощник действий
class Api_Controller_Action_Helper_Model extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
if ($this->_actionController->getRequest()->getModuleName() != 'api') {
return;
}
$this->_actionController->addMapper('account', new Application_Model_Mapper_Account());
$this->_actionController->addMapper('product', new Application_Model_Mapper_Product());
$this->_actionController->addMapper('subscription', new Application_Model_Mapper_Subscription());
}
}
Контроллер
class Api_AuthController extends AMH_Controller
{
protected $_mappers = array();
public function addMapper($name, $mapper)
{
$this->_mappers[$name] = $mapper;
}
public function validateUserAction()
{
// stuff
$accounts = $this->_mappers['account']->find(array('username' => $username, 'password' => $password));
// stuff
}
}
Итак, теперь контроллеру все равно, к каким конкретно классам относятся мапперы - до тех пор, пока существует маппер ...
Но как теперь заменить эти классы на mocks для модульного тестирования, не уведомляя приложение / контроллер о том, что он тестируется? Все, что я могу придумать, - это вставить что-то в помощник действий для обнаружения текущая среда приложения и загрузка макетов напрямую:
class Api_Controller_Action_Helper_Model extends Zend_Controller_Action_Helper_Abstract
{
public function preDispatch()
{
if ($this->_actionController->getRequest()->getModuleName() != 'api') {
return;
}
if (APPLICATION_ENV != 'testing') {
$this->_actionController->addMapper('account', new Application_Model_Mapper_Account());
$this->_actionController->addMapper('product', new Application_Model_Mapper_Product());
$this->_actionController->addMapper('subscription', new Application_Model_Mapper_Subscription());
} else {
$this->_actionController->addMapper('account', new Application_Model_Mapper_AccountMock());
$this->_actionController->addMapper('product', new Application_Model_Mapper_ProductMock());
$this->_actionController->addMapper('subscription', new Application_Model_Mapper_SubscriptionMock());
}
}
}
Это только кажется неправильным ...