Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to inject mock classes into controllers (without having the controller aware of the tests)
    text
    copied!<p>This is a follow-on from a previous question I had: <a href="https://stackoverflow.com/questions/6222001/how-to-decouple-my-data-layer-better-and-restrict-the-scope-of-my-unit-tests">How to decouple my data layer better and restrict the scope of my unit tests?</a></p> <p>I've read around on Zend and DI/IoC and came up with the following changes to my code:</p> <p><strong>Module Bootstrap</strong></p> <pre><code>class Api_Bootstrap extends Zend_Application_Module_Bootstrap { protected function _initAllowedMethods() { $front = Zend_Controller_Front::getInstance(); $front-&gt;setParam('api_allowedMethods', array('POST')); } protected function _initResourceLoader() { $resourceLoader = $this-&gt;getResourceLoader(); $resourceLoader-&gt;addResourceType('actionhelper', 'controllers/helpers', 'Controller_Action_Helper'); } protected function _initActionHelpers() { Zend_Controller_Action_HelperBroker::addHelper(new Api_Controller_Action_Helper_Model()); } } </code></pre> <p><strong>Action Helper</strong></p> <pre><code>class Api_Controller_Action_Helper_Model extends Zend_Controller_Action_Helper_Abstract { public function preDispatch() { if ($this-&gt;_actionController-&gt;getRequest()-&gt;getModuleName() != 'api') { return; } $this-&gt;_actionController-&gt;addMapper('account', new Application_Model_Mapper_Account()); $this-&gt;_actionController-&gt;addMapper('product', new Application_Model_Mapper_Product()); $this-&gt;_actionController-&gt;addMapper('subscription', new Application_Model_Mapper_Subscription()); } } </code></pre> <p><strong>Controller</strong></p> <pre><code>class Api_AuthController extends AMH_Controller { protected $_mappers = array(); public function addMapper($name, $mapper) { $this-&gt;_mappers[$name] = $mapper; } public function validateUserAction() { // stuff $accounts = $this-&gt;_mappers['account']-&gt;find(array('username' =&gt; $username, 'password' =&gt; $password)); // stuff } } </code></pre> <p>So, now, the controller doesn't care what specific classes the mappers are - so long as there is a mapper...</p> <p>But <strong>how do I now replace those classes with mocks for unit-testing without making the application/controller aware that it is being tested?</strong> All I can think of is putting something in the action helper to detect the current application enviroment and load the mocks directly:</p> <pre><code>class Api_Controller_Action_Helper_Model extends Zend_Controller_Action_Helper_Abstract { public function preDispatch() { if ($this-&gt;_actionController-&gt;getRequest()-&gt;getModuleName() != 'api') { return; } if (APPLICATION_ENV != 'testing') { $this-&gt;_actionController-&gt;addMapper('account', new Application_Model_Mapper_Account()); $this-&gt;_actionController-&gt;addMapper('product', new Application_Model_Mapper_Product()); $this-&gt;_actionController-&gt;addMapper('subscription', new Application_Model_Mapper_Subscription()); } else { $this-&gt;_actionController-&gt;addMapper('account', new Application_Model_Mapper_AccountMock()); $this-&gt;_actionController-&gt;addMapper('product', new Application_Model_Mapper_ProductMock()); $this-&gt;_actionController-&gt;addMapper('subscription', new Application_Model_Mapper_SubscriptionMock()); } } } </code></pre> <p>This just seems wrong...</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload