dagfinn | 10 June, 2008 13:40
I came across a Zend Framework (ZF) example I wanted to refactor. You really have to have unit test coverage to refactor effectively, and since there were no tests, I started trying to find out how to test it. There didn't seem to be a wealth of information available on the web, so I've tried to figure it out by myself.
Several challenges presented themselves. It might seem as if the ZF controller system is not optimally designed for testing action controllers, but there are always ways to get around obstacles.
A ZF action controller (which is really just a group of actions collected in a class) always extends Zend_Controller_Action. (For an introduction, see the official QuickStart).
The one I was playing with was an authentication controller:
class AuthController extends Zend_Controller_Action...
That's all we need to know about the specific class under test for now.
I always like to set up the basic objects for the test as instance variables in the setUp() method, so that I can write many small test methods exercising them in various ways. To even get started testing an action controller, we need to instantiate it outside its usual environment, the Zend Front Controller. It requires a request object and a response object:
class AuthControllerTest extends UnitTestCase { function setUp() { $this->request = new Zend_Controller_Request_Http(); $this->response = new Zend_Controller_Response_Cli(); $this->controller = new AuthController($this->request,$this->response); }
(I'm using SimpleTest here, but the same techniques should apply to PHPUnit with different syntax.)
The challenge increases increase when we want to use View Helpers, such as the flash messenger. When programming the action controller, it looks like this:
$flashMessenger = $this->_helper->FlashMessenger;
To test this meaningfully, we need to replace the flash messenger with a mock object. That means also having to replace $this->_helper, which is a "helper broker" object.
First, we generate the mock classes:
Mock::generate('Zend_Controller_Action_HelperBroker','MockHelperBroker'); Mock::generate('Zend_Controller_Action_Helper_FlashMessenger','MockFlashMessenger');
Unfortunately, the helper broker is a protected instance variable, with no apparent way to change it. But it's easy to fix by adding a setter method to the action controller class:
class AuthController extends Zend_Controller_Action... public function setHelperBroker($helperBroker) { $this->_helper = $helperBroker; }
This allows us to set up the mock helper broker and let it return the flash messenger:
$this->helperBroker = new MockHelperBroker; $this->controller->setHelperBroker($this->helperBroker); $this->flashMessenger = new MockFlashMessenger; $this->helperBroker->setReturnValue( '__get',$this->flashMessenger,array('FlashMessenger'));
Now we can use the mock objects to test an action which is supposed to send a flash message:
function testIdentifyActionSendsFlashMessage() { $this->flashMessenger->expectOnce( 'addMessage', array('Please provide a username and password.')); $this->controller->identifyAction(); }
That's as far as I'm going with this now. There may be more later.
| « | June 2008 | » | ||||
|---|---|---|---|---|---|---|
| Su | Mo | Tu | We | Th | Fr | Sa |
| 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 | |||||