I’m an increasingly big fan if unit/functional testing. While not necessarily using TDD I am aiming for comprehensive code coverage in close proximity to writing any bit of code.

With that on mind I have been implementing the Laravel PHP framework in my latest project. Laravel has great testing built in, greatly encouraging its use. (I realize that in a purist sense what I’m doing here is really functional testing as opposed to unit testing).

Rather than pour over tons of documentation I have been pleased with how much I’m learning about Laravel through the use of tests. Specifically I have been writing some custom authentication filters and routes to be used as an API for mobile apps. I have learned as much about Laravel from watching my tests fail as I have from the docs.

For example, consider this code:

Auth::login($apiToken->user());

I am first retrieving a valid API token from the http header. My ApiToken model has a belongsTo relationship with the User model. Laravel makes this relationship easy to retrieve by simply querying my API token and then getting the related User to pass to the login method of the Auth facade.

That all looks well and good except it was failing my auth tests for logging in via a token. The exception was telling me:

ErrorException: Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, instance of Illuminate\Database\Eloquent\Relations\BelongsTo given

Laravel is complaining that I’m not passing a valid User model to the Auth::login() method. After fiddling with the tests and routes code I realized my mistake: The () after the ->user relationship. Even though belongsTo relationships are defined as a function like:

public function user()
{
    return $this->belongsTo('User');
}

The reality is that the relationship is called like a property: $apiToken->user instead of as a function: $apiToken->user(). Calling the property returns a proper related model where calling it as a function returns a BelongsTo object.

So functional testing showed me my coding error early on rather than trying to debug from an http client and also taught me about using the belongsTo relationship. Yes, the Eloquent docs do show the usage without the parenthesis, but I missed the distinction on my reading of the documentation.

As I wire up more and more functional tests to exercise my models, controllers and routes I get the double blessing of learning the framework more intimately and building a nice suite of tests for the future lifespan of this product.

Just in case anyone wants it, here is the AuthTest functional test I’m presently using to exercise my authentication by API token:

public function test_auth_token_with_expiration_event_index_access()
{
    Route::enableFilters();
    // Make sure we start logged out since other tests might have us in a logged in state
    Auth::logout();
    // Create temporary token to test against
    ApiToken::where('token', '=', 'abcd1234')->delete();
    $token = ApiToken::create([
        'token' => 'abcd1234',
        'user_id' => 1,
        'expiration' => date('Y-m-d', strtotime('+1 week')),
        'app_id' => 1
    ]);
    $response = $this->call('GET', '/event', array(), array(), array(
        'HTTP_X-AUTH-TOKEN' => 'abcd1234'
    ));
    $this->assertGreaterThan(0, Auth::id());
    $this->assertResponseStatus(200);
}