Rowan Merewood Experiments in software engineering

3Jul/114

Mocking Action Helpers in Zend Framework

Zend Framework provides the Zend_Test_PHPUnit_ControllerTestCase class to allow unit testing of controllers. However, I ran into some problems when attempting to test controllers that made use of action helpers as there was no immediately obvious way of mocking the calls. Specifically, I had a little helper that was setting up an instance of Zend_Auth for me with the relevant storage and adapter settings for the application. The controller looked a little bit like this:

1
2
3
4
5
6
7
8
9
10
11
12
class ExampleHelperController extends Zend_Controller_Action
{
    public function indexAction()
    {
        // return an instance of Zend_Auth
        $auth = $id = $this->_helper->auth();
        // get the identity of the logged in user
        $userId = $auth->getIdentity();
        // store their ID in the view
        $this->view->userId = $userId;
    }
}

The ideal option would be to mock the _helper() object however this is an instance of Zend_Controller_Action_HelperBroker which is instantiated directly in the constructor and no setter method is available. The HelperBroker uses the Singleton pattern to manage its instance of Zend_Controller_Action_HelperBroker_PriorityStack and conveniently provides a static addHelper method. This allows us to push a mocked instance of our helper onto the stack before the controller is set up. There's a fair amount of logic in adding the helper though, so we need to mock a few methods on the helper to return the right values:

  • getName(): should return last part of the class name of the mocked helper.
  • setActionController(): is part of the helper's fluent interface, so needs to return the mock itself.
  • direct(): is the actual call made from the controller and returns whatever mock data is expected from the helper.

Finally, the entire process can be put together as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class HelperControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    public function testIndexAction()
    {
        // the mock Zend_Auth object to return from the helper
        $auth = $this->getMock('Zend_Auth', array(), array(), '', false);
        $auth->expects($this->once())
            ->method('getIdentity')
            ->will($this->returnValue(1234));
 
        // the mock helper used by the controller
        $helper = $this->getMock('Wfb_Controller_Helper_Auth', array(), array(), '', false);
        // set the identifier for the mock
        $helper->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('Auth'));
        // mock the call that links in the controller
        $helper->expects($this->any())
            ->method('setActionController')
            ->will($this->returnValue($helper));
        // mock the call our controller actually makes
        $helper->expects($this->once())
            ->method('direct')
            ->will($this->returnValue($auth));
 
        // push the helper onto the stack
        Zend_Controller_Action_HelperBroker::addHelper($helper);
 
        $this->dispatch('/helper_controller');
    }
}

This method does feel a bit clunky as it's unfortunately tying the test to the internal logic controller, helper broker and helper stack. An alternative approach may be to extend the controller to allow setting of the helper broker directly, however again the controller has a number of dependencies on it that would need to be mocked anyway. If anyone has a more elegant solution, I'd certainly be interested in hearing it.

Filed under: Hacks Leave a comment
Comments (4) Trackbacks (0)
  1. Yay! Thanks for posting this, Rowan.

    Couple of proof-reading nits;

    1) “logic in adding helper” could do with “a” or “the” before “helper”, or pluralise “helper”
    2) more a matter of personal taste, but I like the function arrows to be lined up when using fluent interfaces

  2. 1) Noted and updated, cheers!
    2) Ah, indentation conventions… we could be here all day. I’ve stooped to using spaces as per the standard, but I can’t bring myself to use arbitrary indents based on the length of a variable name.

  3. Fantastic – thanks – saved me a massive headache :)

  4. New to Zend f , incredibly useful ;)


Leave a comment

No trackbacks yet.