Controller Testing with the FlashMessenger in Zend Framework


During a recent project, I encountered problems with the flash messenger not playing ball with PHPUnit. The problem, the FlashMessenger using a session namespace, and trying to start the session.

Additionally to this problem, how do you test that the flash message is set as you’d expect (or not as the case may be)

The answer to both of these problems, lies in the same solution. a Mock Object.

PHPUnit has a handy feature for mocking objects quickly, and setting some expectations about what should happen to them during their lifecycle, such as, which methods are called, how many times, and with what arguments.

To demonstrate how to mock the flash messenger, consider the following snippet:

<?php
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    public function setUp()
    {
         // bootstrap your application
         // See DragonBe's blog for more info
         // http://www.dragonbe.com/2009/11/unit-testing-with-zend-framework-18.html
    }

    public function testIndexAction()
    {
        $mockMessenger = $this->getMock('Zend_Controller_Action_Helper_FlashMessenger',
                                        array('addMessage'),
                                        array(),
                                        'IndexActionTest_FlashMessenger',
                                        false);
        $mockMessenger->expects($this->never())
                      ->method('addMessage');
        Zend_Controller_Action_HelperBroker::addHelper($mockMessenger);
        $this->request->setRequestUri('/')
                      ->setMethod('GET');
        $this->application->run();
        $this->assertFalse($this->response->isRedirect());
    }

    public function testNewAction()
    {
        $mockMessenger = $this-vgetMock('Zend_Controller_Action_Helper_FlashMessenger',
                                        array('addMessage'),
                                        array(),
                                        'NewAction_Test_FlashMessenger',
                                        false);
        $mockMessenger->expects($this->once())
                      ->method('addMessage')
                      ->with('Item Created');
        Zend_Controller_Action_HelperBroker::addHelper($mockMessenger);
        $this->request->setRequestUri('/new')
                      ->setMethod('POST')
                      ->setPost(
                            array(
                                'foo' => 'bar',
                                'baz' => array(1, 2)
                            )
                      );
        $this->application->run();
        $this->assertTrue($this->response->isRedirect());
    }
}

This will test two actions, an indexAction and a newAction in the index controller.

In the IndexAction test, we are creating a mock messenger to overwrite the built in flash messenger action helper. We then tell it to expect that addMessage is never called. PHPUnit will then add the assertions that it should not be called, and fail if it is.

Likewise in the NewAction test we create a mock messenger, and tell it to expect that the addMessage method is called, and the arguments it should be called with (in this case, as string stating that the item was created).

,

  1. #1 by Bard on March 17, 2012 - 12:48 pm

    Would it not be easier to check the output for a content of a message we set? To know if it was set or not? This way we can even check the type of a message (for example an warning, or success type).

  2. #2 by ryan on March 17, 2012 - 12:59 pm

    Bard :

    Would it not be easier to check the output for a content of a message we set? To know if it was set or not? This way we can even check the type of a message (for example an warning, or success type).

    Easier? No.
    Because if you only check for the output, then you will get fatal errors because of the use of Zend_Session repeatedly across your tests (the session will already be started in the first, and cause problems in subsiquent tests).
    You can also check the type of the message passed to the flash messenger within the expectation setup of the mock (by asserting what is passed to addMessage)

  3. #3 by miholeus on March 31, 2012 - 10:53 am

    Man, it’s really great :) I’ve searched how to do that, nice solution with mocks. Thank you!

Comments are closed.