Laravel 7 Application Testing: Explain This To Me Like I'm Five (part 1)

Updated on August 18, 2020

I have a deep, dark secret... I have been a web developer for over 10 years and I have never written a unit test. I know, I know... how could I have allowed this to happen!? I have been hearing about TDD (Test Driven Development) for a very large chunk of my career, but always being on small developments, many times running solo, I had the false belief that implementing unit testing was going to be too much overhead. I was a little bit right, but mostly completely wrong.

The company I currently work for recently hired a Laravel development shop called Vehikl. Shout out to my Vehikl peeps! I joke with them and tell them that they are the Laravel devs on the mountain. Because they focus on delivering the highest quality code and end product, they push to have many best practices in place. At the time they came on, our in-house development team had written a combined zero number of unit testings. I am not just talking about the application we were working on at the moment, I mean in our entire careers. By the way, there is over 60 years of development experience on our small team of 5 developers. Vehikl is forcing us to get with the times and stop procrastinating. So this is me procrastinating no longer!

One of many side projects

As of the writing of this specific sentence, I have never personally written a unit test on my own, without any Vehikl supervision. I want to bring you on my journey as I attempt to understand the how and the why of what is going on and how you can also, hopefully, finally understand how to unit test your Laravel application.

I have been working on a side project for about a month now and have written a total of zero (0) unit tests. I imagine a lot of you have projects in similar stages, so I encourage you to follow along with your own project as we jump into this rabbit hole.

DISCLAIMER: I am basing this tutorial on a relatively fresh Laravel 7 installation. Laravel versions 6 and below have different commands to run the unit testing. I will add side notes where applicable. Apologies if I miss one.

Making my life so much easier

Laravel comes prebuilt with PHPUnit. In your root directory, you will see a phpunit.xml file. Let's checkout the testsuites block:

It looks like the nested testsuite blocks serve as pointers to where our tests are going to live. In the Laravel root directory, there is a /tests folder that gets created on installation. This folder contains two additional folders by default: tests/Feature & tests/Unit. The name attributes on the nested testsuite blocks look like they reference these folder names. I imagine if we want to create additional folders, we could created an additional testsuite block along with the folder. Maybe something like this:

The suffix attribute on the nested directory element looks like it requires that all future created tests end with "Test.php". For example:

./test/Unit/LoginControllerTest.php

In addition to the Feature and Unit folders within the root/tests folder, there are two base files:

./tests/CreatesApplications.php

CreatesApplication Trait

CreatesApplication Trait

CreatesApplications is a default trait that boots up the Laravel application when we are running the tests. I imagine this trait is being used in the next file.

./tests/TestCase.php

TestCase Base Class

TestCase Base Class

TestCase is the base class that all other test cases are going to extend. It does use the CreatesApplication trait, which will be available to all classes that extend this one. Gotta love Laravel!

Let's get this show on the road!

With a fresh install of Laravel, we get two example tests. Let's see what they look like:

./tests/Feature/ExampleTest.php

Default Feature ExampleTest

Default Feature ExampleTest

First thing to notice is the RefreshDatabase class that is being imported. Though it doesn't look like it is being used for this test, you can bet that we will need to use this at some point soon. We have one basic test here that hits the homepage of the application and is expecting a response of 200. Seems pretty straight forward. Unless I messed up somewhere in the routes or the controller, this should pass.

./tests/Unit/ExampleTest.php

Default Unit ExampleTest

Default Unit ExampleTest

The example unit test is definitely simpler. We are expecting a true response and we are passing in true. Nothing to see here.

Now that we have reviewed how PHPUnit is loading the tests and how the tests are currently structured, lets run these babies!

How do I run my tests?

As any good Laravel developer, I reach for my favorite tool:

php artisan

Cool! There is a test command:

php artisan test
All Passed, All Good!

All Passed, All Good!

We did it! We successfully executed our first test run of the application. Laravel really makes this super easy!

SIDE NOTE: I reviewed an older project currently on Laravel 6, and it does not contain the "php artisan test" command. Instead you can run the tests with the "vendor/bin/phpunit" command in the command line. I have not looked at versions older than 6 as of this writing.

Taking Baby Steps

The purpose of this first blog post in this series was to review how Laravel comes pre-packaged with PHPUnit, how the tests are autoloaded and how to run the damn things. I feel much better about testing after reviewing the files and seeing how everything is structured. Thanks Taylor for allowing my procrastination to pay off. I'm sure integrating unit testing was a degree more difficult years back, but so far, I'm not seeing a reason why I wouldn't be able to start integrating Unit and Feature testing into my day to day development.

My current employer is making it a point to have all the developers submit features with tests already built, with a push to eventually move to full on TDD. I need to get my testing chops up to par, so I am going to be blogging more often in order to make more progress. It really helps me to absorb the material when I am writing about it, so believe me when I tell you that this is probably benefiting me more than it is benefiting you. Though I truly hope it serves as an easy way for anyone to start testing, no matter how mature the application may be.

Since I need to learn quickly, I will be blogging quickly. Check back often for additional blogs in the series. Till next time!