I'm attempting to clean up an existing application by writing unit tests for some legacy code (and updating it along the way). I've rewritten a number of libraries and I've really been loving the TDD approach. However, now it's time to move on to testing some controllers, and I've run into a problem on the very first set of tests. I'm following the explanations in Jeffery Way's Laravel Testing Decoded.
The goal here is to test my login route: http://my-development-server/login
. The code should work like this: first, check to see if someone is already logged in - if they are, redirect them to the dashboard (the main page in the app). Otherwise, render the login page. Pretty straight forward.
Here are the routes involved:
Route::get('login', array(
'as' => 'login',
'uses' => 'MyApp\Controllers\AccountController@getLogin',
));
Route::get('/', array(
'as' => 'dashboard',
'uses' => 'MyApp\Controllers\DashboardController@showDashboard',
'before' => 'acl:dashboard.view',
));
Here's the AccountController::getLogin
method:
public function getLogin()
{
// Are we logged in?
if (\Sentry::check())
return Redirect::route('dashboard');
// Show the page.
return View::make('account.login');
}
I'm using the Sentry
library for user authentication.
And here's my first test:
class AccountControllerTest extends TestCase {
public function tearDown()
{
Mockery::close();
}
public function test_login_alreadyLoggedIn()
{
// arrange
//
\Sentry::shouldReceive("check")
->once()
->andReturn(true);
// act
//
$response = $this->call("GET", "/login");
// assert
//
$this->assertRedirectedToRoute("dashboard");
}
}
This test emulates the "user attempts to log in when they're already logged in" case. check
returns true (already logged in) and the user is redirected to the route named dashboard
. It works perfectly, test passes.
Next, I add a new test, to test the "user attempts to log in when nobody's logged in" case. Here's the code for that test:
public function test_login_notLoggedIn()
{
// arrange
//
\Sentry::shouldReceive("getUser")
->twice()
->andReturn(null);
\Sentry::shouldReceive("check")
->once()
->andReturn(false);
// act
//
$response = $this->client->request("GET", "/login");
// assert
//
$h2 = $response->filter("h2");
$this->assertEquals("Please sign in", $h2->text());
}
When I run this test, the first test passes but I get a NotFoundHttpException
in the second test method.
There are a couple of strange things about this problem:
if I comment out the first test method (test_login_alreadyLoggedIn
), the second test passes.
if I reverse the order of the two test methods, test_login_notLoggedIn
passes and test_login_alreadyLoggedIn
fails (ie. the first method in the class passes and the second fails).
This looks to me like some sort of configuration issue - after the first test (which passes), something is messed up and it cannot make the request in the second test - but I'm at a loss. I've gone over the book several times and google but can't find any reference to any configuration that I'm missing.
Any suggestions?