(Note, this example was using Zend Framework 1.10, so things might change going forwards).
As a lapsed tester, I've made the commitment to build out our Zend Framework powered application using tests going forward. The first two modules for the app *should* have been done with tests, and for that I hang my head with shame. Now that I've invested the work in creating a continuous integration environment using Hudson, there is no longer an excuse to not write tests. Especially when I can get tests run automatically every time I commit code.
Anyway, I was asked to implement a new feature for the application: a list of all transactions for a fantasy baseball league, sorted by date. What a perfect excuse to write some tests! The initial problem though was how do I simulate logging in a user so I can see this page, which was protected by authentication using Zend_Auth. So I started my scouring the internet for answers.
I found quite a few examples on how to test a controller, using the $this->dispatch('/path/to/action') method but found that I wasn't getting redirected properly to the post-login page. I was passing proper credentials in and everything. Then finally after deciding to go back to basics and read up on just how to test Zend_Auth. After some swearing a few face-palms, I realized what I had been doing wrong.
The tl;dr version: I was forgetting that the unit test itself needed to manually log in the user by speaking with Zend_Auth directly. Here's the testing code for that particular controller:
-
<?php
-
-
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
-
require_once 'Zend/Application.php';
-
-
// Define path to application directory
-
}
-
-
// Define application environment
-
}
-
-
// Ensure library/ is on include_path
-
)));
-
-
class TransactionControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
-
{
-
-
public function setUp()
-
{
-
$this->bootstrap = new Zend_Application(
-
'testing',
-
APPLICATION_PATH . '/configs/application.ini'
-
);
-
parent::setUp();
-
}
-
-
public function loginUser($login, $passwd, $shortLeague)
-
{
-
'login' => $login,
-
'password' => $passwd,
-
'short_league' => $shortLeague
-
);
-
$adapter = new Xmlteam_Auth($authParams);
-
$auth = Zend_Auth::getInstance();
-
$result = $auth->authenticate($adapter);
-
$this->assertTrue($auth->hasIdentity());
-
}
-
-
public function tearDown()
-
{
-
parent::tearDown();
-
}
-
-
public function testOverallBaseballList()
-
{
-
$this->loginUser('test@test.com', '*****', 'bluejays2010');
-
$this->dispatch('/baseball/bluejays2010/transactions/list');
-
$this->assertModule('baseball', 'In baseball module');
-
$this->assertController('transactions', 'In the transactions controller');
-
$this->assertQuery('#tblTransactions', 'Transaction table exists');
-
}
-
}
I'm using a custom authentication adaptor with Zend_Auth, as we need to limit access for a user to a particular league. Perhaps better to do it with Zend_Acl, and since the platform is likely to expand I will end up using that as well. But I am drifting off topic here.
The magic is in that loginUser() method. What I did not realize at the time was that running a test where I asked it to dispatch users to the login page and passed along what would've been entered in the form was not working. Perhaps it was creating an authenticated session OUTSIDE the scope of the test environment. Perhaps it is my sucky code. Either way, it wasn't working.
So, by creating a authenticated login Zend_Auth *inside* the test, I could then safely dispatch my testing code to look at pages requiring authentication. I hope this blog posts helps out others trying to write tests for controllers that are hidden behind Zend_Auth.
Tags: testing, Zend Framework, Zend_Auth

I could be missing something here, but should the Zend_Auth adapter just be stubbed anyway if you're not testing auth functionality?
I just use the following function:
protected function _logIn() {
$user = User::find_by_email('foo@bar.com');
Zend_Auth::getInstance()->getStorage()->write($user);
}
I don't want to test any of the authentication logic, I just want the app to think I've logged in already.
[...] This post was mentioned on Twitter by MWOP, Chris Hartjes. Chris Hartjes said: Blog post on testing #zf controllers hiding behind Zend_Auth -> http://bit.ly/bqg2rj [...]
[...] Hartjes has written an article on how to test Zend Framework controllers which are protected by Zend_Auth. I found quite a few examples on how to test a controller, using the [...]
@Chris
That could work too. I was more interested in getting a test working first, and I can always go back and refactor it to not bother testing the authentication logic.
I've heard lots about phpUnderControl, but not about Hudson. Why did you choose it over phpUC ? More actively maintained? Any specific features you wanted?
Glad you figured out the auth thing. I'm sure your post will help me in future. The more I read about "lean startups", the more I want to try continuous integration & deployment.
[...] http://www.littlehart.net/atthekeyboard/2010/06/03/testing-controllers-hiding-behind-zend_auth/ [...]
[...] Unit-testing controllers protected by Zend_Auth: http://www.littlehart.net/atthekeyboard/2010/06/03/testing-controllers-hiding-behind-zend_auth/ [...]
@Derek
Two reasons I chose Hudson. First was that it came highly recommended by people in the PHP community who are doing continuous integration. Second, we're a mixed shop (some stuff PHP, some stuff Perl, some stuff Java) so we needed something that could handle building all of them.
[...] his blog today Chris Hartjes has a new post about testing your Zend Framework application’s functionality that lives behind a Zend_Auth [...]
[...] his blog today Chris Hartjes has a new post about testing your Zend Framework application’s functionality that lives behind a Zend_Auth [...]
Nice post. Are u using any tool to automate the build of your projects?
Regards.
@Fernando
We're using Hudson to do automated builds on our staging server whenever I commit a change, and using Phing to deploy to production.
[...] Testing Controllers Hiding Behind Zend_Auth [...]