|

How To Test Your Laravel Application

How To Test Your Laravel Application

Laravel leverages the popular PHP testing framework PHP Unit as a dependency, which makes it possible to set up testing facilities on the applications you build with Laravel. If we look inside of our current Laravel installation, we can see there is a tests directory which holds two sub directories. The sub directories are those of Feature and Unit. Of course these are the locations of setting up tests you would like to have for your application. We’ll explore these topics in applying some basic tests to the games application we have been building in the last several tutorials.


tests/Feature/ExampleTest.php

In this directory you would place tests that test the bigger features of the application. These are higher level than unit tests, which would be considered more granular. Let’s take a look at what is in this example test right now.

Expected status code 200 but received 404

Normally, this test would pass when you first install Laravel. We have made a lot of changes however, and built many features into our application that are not part of the default installation. In our case, we should get a 200 OK when we visit the /games route, as that is more of our homepage in this application. Let’s change the test, and re run the test. Note the highlighted change in the test file.

phpunit test pass

Now when we run the test, we get a success.


Using assertSee()

The assertSee() method is a great way to test that your web pages are displaying what they should be. For example, when we visit our /games page, we should see some text that says “We Like Games”. When we manually visit this page, this is what we see.assertsee method in action

How can we turn this into a test? We can update our test just like this:

When we run the test, everything passes nicely.assertsee we like games passing


Given, When, Then in Testing

To test specific functions of your code, you’ll likely want to follow the pattern of Given, When, Then.

  • Given – Given refers to the initial set up of the environment you’d like to test. You might make use of some data, or perhaps even set up a model factory during this step.
  • When – When is the call to the function or method in question. If you are testing a specific method, we call it here.
  • Then – Then is the part where you assert that the result is what you would expect it to be.

Testing Database Functionality

Putting data into, and getting data out of the database is pretty important in our games application. Maybe we should test some of the services that perform these tasks for us. To do this, we first want to set up a testing database. We’ll create a new database called games_testing on our server, then just make a quick update to our .env file to make use of this new database. We set DB_DATABASE=games_testing in the .env file to do this. This new database has no tables in it, we we will need to run the migrations.php artisan migrate games_testing

Our testing database is now set up and we can now work with testing data.the migration on testing database worked


Model Factories

We created a new testing database for our application, but no data exists in the database. This is what model factories are for. We can quickly populate dummy data in our database using factories. A factory is like a blueprint for an eloquent model. Let’s take a look at the user factory that is provided with Laravel.


database/factories/ModelFactory.php

The comments here tell you exactly what a model factory is for: “Here you may define all of your model factories. Model factories give you a convenient way to create models for testing and seeding your database. Just tell the factory how a default model should look.”

Great! Let’s create 3 fake users in the test database using Tinker. We simply type factory(‘App\User’, 3)->create(); at the Tinker command prompt and observe the results.
creating fake users in the database

Browsing our test database with phpmyadmin shows the new fake users are successfully created as well.fake users in phpmyadmin


Populating Fake Games

How can we simulate the process of submitting a new game to the database? The first thing we need to do is figure out exactly what a game submission consists of. For this, we can look at the migration that defines the games table.

It looks like a game consists of the user_id of the user that created the game submission, the title of the game, the publisher of the game, the releasedate of the game, and the image url. The id and timestamps are automatic so we don’t need to include those in the factory. Let’s try to set up a factory with these parameters now.

Now we can try adding some games to the testing database with tinker.adding fake games to the test database

Let’s create a new test with php artisan make:test GameSubmission –unit. This will create a new Test class which lives at tests/Unit/GameSubmission.php and it will look like this:

This gives us the outline of a new test in it’s own class. This way, as you add multiple different tests to your application, you can break them out into their own class and keep things organized and sane. Just like you would properly organize all of your models or controllers, so too can we organize our tests. If we wanted to run just this one test, just type phpunit tests/Unit/GameRetrieval.php instead of phpunit.game retrieval passing
Let’s set up a test to create a new game in the database, fetch the latest games, assert that the inserted game is equal to the retrieved game, then roll everything back using database transactions.

When we run the test, we can see that the inserted game does match the game retrieved from the database. Our test is working.game retrieval passing


What else can we test?

In thinking about the application, we can think of how things should or should not happen. How about the scenario where we have a non authenticated user that tries to visit /games/create to submit a new game? What should happen in that case? We know that a non authenticated user should be redirected to the Log In page. Let’s create a test to verify that.
php artisan maketest RedirectGuestForGameCreation

When we type php artisan make:test RedirectGuestForGameCreation and omit the –unit flag, Laravel sets this test up as a Feature test. If we now take a look in tests/Feature we have a new test stub for us in the file RedirectGuestForGameCreation.php. We can test for this condition with something as simple as follows:

test RedirectGuestForGameCreation passed phpunit

The opposite of this might be that when a logged in user visits /games/create, they should be presented a Game Submission form. We can set up a test for that as well. This is how we might complete that task. First we use php artisan make:test AuthenticatedUserSeesSubmitForm to make that new test case for us. We will then have a new file of AuthenticatedUserSeesSubmitForm.php in the tests/Feature directory.

Great! It looks like this is working well.
AuthenticatedUserSeesSubmitForm test passing


More Tests

Recall that we had set up a query scope created in our Games model that was set up to specifically retrieve games from the database where the publisher is Nintendo. We could create a unit test that verifies this behavior if we like. Actually, that sounds like a good idea, let’s go ahead and set up a nice test for that now. We begin by typing php artisan make:test VerifyNintendoScope –unit. Artisan automatically creates the VerifyNintendoScope.php test file in our tests/Unit directory. Let’s open up that file and apply the Given, When, Then method of setting up a test to test out the Nintendo query scope.

Nice!
how to test query scope in laravel


How To Run All Tests

We’ve created a few tests now and maybe we want to be able to just type phpunit and have all tests run. As it stands now, when we do this only two tests are showing as running. This is because when you create a test class, the name of the class must have a suffix of Test. To fix this we simply use PHP Storm to refactor the tests we have already created to include that Test suffix. So now AuthenticatedUserSeesSubmitForm.php is AuthenticatedUserSeesSubmitFormTest.php, RedirectGuestForGameCreation.php is RedirectGuestForGameCreationTest.php, GameRetrieval.php is GameRetrievalTest.php, and VerifyNintendoScope.php is VerifyNintendoScopeTest.php. In addition to this, we still have an ExampleTest.php in both the Feature and unit directories.

Now we can in fact just type phpunit and have all tests run at once.
how to run all tests at once in laravel

It looks like all of our tests are working.


How To Test Your Laravel Application Summary

In this tutorial, we added some basic testing scenarios to our games application. We tested that an authenticated user can see a form to submit a game, that a guest is redirected if they try to visit /games/create, that the application is correctly fetching games from the database, as well as setting up a test to verify the Nintendo query scope we had created in an earlier tutorial. You can create as many or as few tests as you like, it is up to you and your imagination.