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 4 Comments
29Nov/099

Giving Finger the Twitter

Commands with names that can be interpreted in a juvenile fashion seem to be a long standing tradition in the various Unix-like operating systems out there. One that seems to have fallen out of use is finger. So, to start the learning (and perhaps a little giggling) open a terminal and and let's try fingering ourselves.

1
2
3
4
5
6
7
8
rowan@favabean:~$ finger rowan
Login: rowan                            Name: Rowan Merewood
Directory: /home/rowan                  Shell: /bin/bash
On since Sun Nov 29 15:58 (GMT) on tty7 from :0
4 hours 19 minutes idle
On since Sun Nov 29 16:42 (GMT) on pts/0 from :0.0
No mail.
No Plan.

At the end of the output you can see the rather cynical sounding "No Plan." message. Since we hopefully do have a plan, let's see what's going on there. Straight-faced, type in:

1
man finger

Read through and you should find the excerpt:

1
2
~/.plan ~/.project ~/.pgpkey
These files are  printed as part of a long-format request. The .plan file may be arbitrarily long.

Let's experiment with this in the classic way then:

1
2
3
4
5
6
7
8
9
10
11
rowan@favabean:~$ echo 'Hello, World!' > ~/.plan
 
rowan@favabean:~$ finger rowan
Login: rowan                            Name: Rowan Merewood
Directory: /home/rowan                  Shell: /bin/bash
On since Sun Nov 29 15:58 (GMT) on tty7 from :0
4 hours 30 minutes idle
On since Sun Nov 29 16:42 (GMT) on pts/0 from :0.0
No mail.
Plan:
Hello, World!

All simple enough, so why is it there? A little digging around will uncover a post on alt.folklore.computers in Origins of the finger command. He quotes an email from Les Earnest, the author of finger and it includes an explanation of the Plan feature:

Some people asked for the Plan file feature so that they could explain their absence or how they could be reached at odd times, so I added it. I found it interesting that this feature evolved into a forum for social commentary and amusing observations

This sounds familiar... almost as if filling in your .plan is the equivalent of answering the question "What's happening?"

In which case, let's link our old-school '70s protocol up-to everyone's favourite social network. Since we're keeping the Unix theme, we'll do it by piping a few commands together.

Fetch your status, substituting in your username for rowan_m:

1
http://twitter.com/users/show.xml?screen_name=rowan_m

Strip out everything except your update:

1
2
| grep "<text>"
</text>

Strip out the tags:

1
2
| sed 's/\s*<text>\(.*\)< \/text>\s*/\1/'
</text>

Dump that into your Plan:

1
> ~/.plan

Let's string that all together and see what happens:

1
2
3
4
5
6
7
8
9
10
11
12
rowan@favabean:~$ curl -s http://twitter.com/users/show.xml?screen_name=rowan_m | grep "<text>" | sed 's/\s*</text><text>\(.*\)< \/text>\s*/\1/' > ~/.plan
 
rowan@favabean:~$ finger rowan
Login: rowan                            Name: Rowan Merewood
Directory: /home/rowan                  Shell: /bin/bash
On since Sun Nov 29 15:58 (GMT) on tty7 from :0
4 hours 52 minutes idle
On since Sun Nov 29 16:42 (GMT) on pts/0 from :0.0
No mail.
Plan:
Piping some commands to other commands
</text>

There we go, my current status in my .plan. Obviously you don't want to be running that manually every time, so as a last step you can add it into your crontab. For example, to set it up to run every five minutes use crontab -e and add the following:

1
2
3
# m   h  dom mon do  command
*/5 *  *   *   *   curl -s http://twitter.com/users/show.xml?screen_name=rowan_m | grep "<text>" | sed 's/\s*</text><text>\(.*\)< \/text>\s*/\1/' > ~/.plan
</text>

This has been pretty quick and dirty, so feel free to point out optimisations. I'm sure we can get this down to 10 characters of Perl. ;)

Filed under: Hacks 9 Comments