This afternoon I found a bug in some old code that I’m refactoring and retrofitting unit tests into. Well, not a bug exactly but a Zend Framework controller quirk. It drove me absolutely nuts for ages until I went to Google and found a solution. Imagine the following example which is some methods from a class that extends the ControllerTestCase in the Zend_Test library:
public function testEmptyUrlParameterRedirctsCorrectly()
{
$this->dispatch('/user/profile/');
$this->assertModule('user');
$this->assertController('profile');
$this->assertAction('index');
$this->assertRedirectTo('/user');
$this->assertResponseCode('302');
$this->assertRedirect();
}
public function testInvalidUrlParameterRedirctsCorrectly()
{
$this->dispatch('/user/profile/invalid-username');
$this->assertModule('user');
$this->assertController('profile');
$this->assertAction('index');
$this->assertRedirectTo('/user/invalid');
$this->assertResponseCode('302');
$this->assertRedirect();
}
The controller is expecting a url like /user/profile/username. If the username is invalid or missing altogether we want to test that the page redirects elsewhere and displays any necessary feedback to the user. While this functionality had always seemed to work in the application, the unit tests were failing for some reason. After a bit of assert writing it turned out that the tests were returning a module/controller combination of default/error instead of user/profile. The error was nowhere to be seen in the application and it continued to redirect correctly as it always had.
A quick read on Nabble later and I came away with an interesting tip from Zend developer Matthew Weier O’Phinney.
“Whenever you _forward() or redirect, you should return immediately. As
an example:if (!$form->isValid($request->getPost())) {
return $this->_forward(‘details’);
}If you don’t, the action continues to process. This would definitely
have an impact on redirects as well.”
Now, I’ve always written my redirects in the following way:
$this->_redirect('user');
But after adding the return statement into the legacy code, all the new controller tests passed. I’m not really sure what this implies for any other redirects that have yet to be unit tested as no errors have been thrown by the application logs. It may be possible that redirects only operate this way during unit tests and will return automatically during normal execution. I’ll investigate this soon unless anyone else has any insightful thoughts on the matter?
