Question

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:

  1. if I comment out the first test method (test_login_alreadyLoggedIn), the second test passes.

  2. 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?

Was it helpful?

Solution

For anyone who may run into this problem in the future...

This was caused by problems with my routes.php file. In particular, I organized by routes into a set of files:

  1. accounts.php - contains routes related to "account" functions

  2. admin.php - contains routes related to "admin" functions

  3. etc...

These files were then included in my routes.php file with require_once. This works fine for my application, but for some reason, the routes were not loaded properly during testing. The solution is to move my routes back to the routes.php file until I can find a better way to organize them.

OTHER TIPS

You can solve this problem by replacing your require_once() to require()

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top