So in this article I’m going to explain how to test every route in a laravel application. I usually name all the routes in my application, so essentially, every route in my application has some sort of sanity test.
Here is a 1 minute video of me writing all the tests for my application with this script.
The TLDR; gist of this article is that I can run a command
$ missing-route-tests
And that command will generate some testing code for me based on routes that are missing. Something like this:
/**
* @route users.edit
*/
public function test_users_edit()
{
$this->markTestIncomplete('This test is incomplete');
$response = $this->call('GET', '/users/{users}/edit');
$this->assertEquals(200, $response->status());
}
This essentially means two things.
- I don’t have to keep up with all routes I have and have not tested.
- It also creates a boilerplate for me to get started testing.
You can find the missing-routes-test
script HERE.
Laravel Testing Basics: Getting Started With A Single Test
Since most applications have users, let’s create a RESTful resource to manage our users in our application. So let’s add a resourceful route to our routes.php
file.
Route::resource('users', 'UsersController');
Next we need a resource controller, so let’s run the command to create it for us.
$ php artisan make:controller UsersController --resource
Next we want to test a route in Laravel, I can create it using artisan
$ php artisan make:test UsersTest
That gets us some code generated out that looks something like this
class UsersTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testExample()
{
$this->assertTrue(true);
}
}
At this point, I want to test a route. Therefore, I add a method and use Laravel’s awesome testing methods to call the /users url.
/**
* Check out the /users index page
*/
public function test_users_index()
{
$response = $this->call('GET', '/users');
$this->assertEquals(200, $response->status());
}
Now when we run phpunit we get that green that everyone likes.
kelvinvidel:~/space/blog$ phpunit
PHPUnit 4.8.24 by Sebastian Bergmann and contributors.
..
Time: 135 ms, Memory: 13.00Mb
OK (2 tests, 3 assertions)
Granted, our test is really simple. It only checks for a response status of 200. If we navigate to this page it is blank because our UsersController::index()
is empty.
Testing ALL The Things (Routes)
So are we done? No. We’ve only tested 1 route so far. Laravel ships with a nice artisan command to view all our routes.
$ php artisan route:list
For our basic users management application this spits out the following
We could manually go through this list and try to test at our own pace. But this method is prone to human errors and it’d be better to programmatically scan for the routes we have not yet tested.
Thus I run the following command to see which tests are missing from our users app.
$ missing-route-tests
This outputs the following
/**
* @route users.index
*/
public function test_users_index()
{
$this->markTestIncomplete('This test is incomplete');
$response = $this->call('GET', '/users');
$this->assertEquals(200, $response->status());
}
/**
* @route users.create
*/
public function test_users_create()
{
$this->markTestIncomplete('This test is incomplete');
$response = $this->call('GET', '/users/create');
$this->assertEquals(200, $response->status());
}
/**
* @route users.store
*/
public function test_users_store()
{
$this->markTestIncomplete('This test is incomplete');
$data = [];
$response = $this->call('POST', '/users', $data);
$this->assertEquals(200, $response->status());
}
/**
* @route users.show
*/
public function test_users_show()
{
$this->markTestIncomplete('This test is incomplete');
$response = $this->call('GET', '/users/{users}');
$this->assertEquals(200, $response->status());
}
/**
* @route users.edit
*/
public function test_users_edit()
{
$this->markTestIncomplete('This test is incomplete');
$response = $this->call('GET', '/users/{users}/edit');
$this->assertEquals(200, $response->status());
}
/**
* @route users.update
*/
public function test_users_update()
{
$this->markTestIncomplete('This test is incomplete');
$data = [];
$response = $this->call('PUT', '/users/{users}', $data);
$this->assertEquals(200, $response->status());
}
/**
* @route users.destroy
*/
public function test_users_destroy()
{
$this->markTestIncomplete('This test is incomplete');
$data = [];
$response = $this->call('DELETE', '/users/{users}', $data);
$this->assertEquals(200, $response->status());
}
Now when I run phpunit
again, I at least have a rough idea of how many routes we have yet to test.
How it works?
Right now I’m using annotations to mark a named route as tested. I decided for this approach because it seems easy. Another approach that might work is to run phpunit and keep track of which routes were called during the entire process. After that was finished, we could compare our list of routes to the entire list using Route::getRoutes()
. I opted for the annotation route just because I wanted something quick and easy.
Again you can find the script HERE.
If you find yourself using this or have some sort of improvements or even a better way for testing all the routes in your application, please leave me a comment. Thanks!