|

How To Create A Feature Test In Laravel

How To Create A Feature Test In Laravel

Since we are doing test driven development, we need to actually create tests for features before we even build them. In this tutorial, that is exactly what we will do. The first thing, or feature, that our forum project will have is that a user can view threads. We can navigate to the tests folder and rename the boilerplate ExampleTest.php to ThreadsTest.php. Before we do that however, we will need to set up our testing environment, so that will be the first step.


Configure In Memory Sqlite Database Testing

For this step we need to configure the phpunit.xml file. We can specify both the DB_CONNECTION and DB_DATABASE values as shown.

What this is telling Laravel is that when we run tests in PHP Unit, it will use the in memory Sqlite option.


Leverage The Database Migrations Trait

In our tests, we can use the database migrations trait for testing. This way for every single test that runs, the database will be migrated if needed, data populated or removed, and once the test is complete everything will get rolled back. This is pretty neat actually. Here is the code that is powering this migration feature.


Create The First Feature Test

With these items in place now, we can create the first test in our ThreadsTest.php file. We want users to be able to browse threads so we will create this test named as a_user_can_browse_threads. This is simply a function of the ThreadsTest class. Here is the code we can start with.

So far all this test is saying is, when a user visits the /threads endpoint, the response should be a 200 OK. So we can run the test.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

W.                                                                  2 / 2 (100%)

Time: 646 ms, Memory: 6.00MB

There was 1 warning:

1) Warning
No tests found in class "Tests\Feature\ThreadsTest".

WARNINGS!
Tests: 2, Assertions: 1, Warnings: 1.

Hmm, I expected the failure, but not that one. Let’s see if we can fix this. Ok, Interesting. It looks like I needed to use a different naming convention on the function test name. Perfect, we can update our test name from a_user_can_browse_threads to test_a_user_can_browse_threads and we should be good to go. Here is the updated Test case.

Let us once again run our test.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

F.                                                                  2 / 2 (100%)

Time: 789 ms, Memory: 8.00MB

There was 1 failure:

1) Tests\Feature\ThreadsTest::test_a_user_can_browse_threads
Expected status code 200 but received 404.
Failed asserting that false is true.

/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:78
/home/vagrant/Code/forumio/tests/Feature/ThreadsTest.php:19

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

Ah ha. It fails. We get an error of a bad 404 response. The 404 response means not found, as we learned about in our http status codes tutorial. We expected this test to fail because we don’t even have a route for the /threads endpoint. So with testing, we pretty much always have the test fail at first and then keep fixing small things until the test finally passes. So let’s try to fix things up and make this test pass. First, we can add the route.

Real quick, it looks like when we first created our controllers they were not in the plural form. We can fix that with a quick refactor in PHP Storm. Make sure to complete this step if you are following along.

Refactor ThreadController to ThreadsController
refactor to rename controller method 1

Refactor ReplyController to RepliesController
refactor to rename controller method 2

With these refactors in place, let’s just add a quick snippet to the index method in our ThreadsController file so we can run the test again. We’ll simply return the string of ‘hi’, and this should be enough to generate a 200 OK status back to us.

Let’s run the test again.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

F.                                                                  2 / 2 (100%)

Time: 796 ms, Memory: 10.00MB

There was 1 failure:

1) Tests\Feature\ThreadsTest::test_a_user_can_browse_threads
Expected status code 200 but received 500.
Failed asserting that false is true.

/home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:78
/home/vagrant/Code/forumio/tests/Feature/ThreadsTest.php:19

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.

What the?! Things have gone from bad to worse. Initially we had a failure due to a 404 not found message. Now we are busting out a full status code 500, or in other words, a catastrophic failure. When in doubt, clear the cache, as well as do a composer dump.

vagrant@homestead:~/Code/forumio$ php artisan cache:clear
Cache cleared successfully.
vagrant@homestead:~/Code/forumio$ composer dump
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Package manifest generated successfully.

Let’s run that test one more time.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 669 ms, Memory: 8.00MB

OK (2 tests, 2 assertions)

BOOM! For the first time so far, we get a passing test. LOL. Of course we know that we actually want the test to do more than just confirm a status 200 code on the response and we will tackle that shortly. At this time, let’s use artisan to generate some auth scaffolding so we can use some of that generated html in our project. We covered this topic in the Laravel user registration tutorial.

vagrant@homestead:~/Code/forumio$ php artisan make:auth
Authentication scaffolding generated successfully.

This creates great looking login and register pages that are fully functional for you. As you can see, they look quite nice.
good looking login auth scaffolding

Now what we are going to do is create the view file we need for our threads test, and borrow some of the markup that is created with the auth files we just created. So in the /resources/views/threads directory we can create index.blade.php. What we can now do is open the home.blade.php file which was generated for us, then copy paste into our file while making some modifications so that it gives us just a basic work up for our view.

While we are at it, let’s also fix the index() method in our ThreadsController. What we can do to start is to simply fetch all threads from the database, pass them to the view, and render them out on the page. Here is our updated controller.

With everything in place, we can once again run our tests in PHP Unit.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 1.16 seconds, Memory: 8.00MB

OK (2 tests, 2 assertions)

Sweet! We are passing like a boss. That means we can try loading that page in the browser and it should work. Let’s try it out.
threads test is working in the browser


Making Tests More Granular

So we can see that everything is working so far both from our test, and in the browser. The test as it stands now only checks for a 200 status code. Pretty much if any page loads, no matter what it is, you’ll get a 200. That is not incredibly helpful. We likely also should assert that the test verifies correct output on the page and so forth. Let’s adjust our test a bit here.

This looks a little more realistic now. In our test function, we now create a thread and load it to the test database. After this, we send a get request to the /threads endpoint and check the response. This time around, we confirm or assert, that we see the actual title of the thread on the page. We also continue to assert that we receive a 200 OK status message. We can run the tests again and see all assertions are working correctly which is nice.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 1.7 seconds, Memory: 8.00MB

OK (2 tests, 3 assertions)

Feature Test Two

Ok I’m feeling pretty good about the first feature being set up with tests, and built out to work correctly. A user can browse threads feature is tackled. Now, let’s create a new feature. Users should also be able to view a single thread. Following test driven development, we will start creating the test, before we even start building out that feature. We can add the following code to our ThreadsTest class to get this going.

Much like the first test, we now test browsing a specific thread. So we create a new thread, visit the /threads/{id} endpoint, confirm we see the title, and confirm we get a status 200. We know this will fail if we test this right now but let’s go ahead and test it anyway.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

.F.                                                                 3 / 3 (100%)

Time: 1.35 seconds, Memory: 8.00MB

There was 1 failure:

1) Tests\Feature\ThreadsTest::test_a_user_can_read_a_single_thread
Failed asserting that '\n
\n
    \n
        \n
        \n
        \n
\n
        Page Not Found\n
\n
        \n
        \n
\n
        \n
        \n
    \n
    \n
        
\n
\n
\n Sorry, the page you are looking for could not be found.
\n
\n
\n \n \n ' contains "Praesentium corrupti quia excepturi ea ut placeat quo.". /home/vagrant/Code/forumio/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:236 /home/vagrant/Code/forumio/tests/Feature/ThreadsTest.php:27 FAILURES! Tests: 3, Assertions: 4, Failures: 1.

Whoa. That’s a pretty good blow up right there. What happens here, is that since we are trying to assert a particular string of text on the page, we see this big blob of html that gets returned in the test results. If you look closely you can see though that the main message is Failed asserting that (the html) contains “Praesentium corrupti quia excepturi ea ut placeat quo.”. Ok fair enough, let’s build out the plumbing we need to make this test pass.

We need a route for this feature so let’s add one now.

We also need the show() method to be built out. We can do that like so for the show() method in the ThreadsController. Note that since we are injecting a model as a parameter to the show method, Laravel will work a little bit of magic with Route Model Binding.

Finally, we need a view file to display the results. Go ahead and create the show.blade.php file inside of the resources/views/threads directory. We can populate the file like so.

Everything is now in place for our second feature of a user can view a single thread. Let’s run our tests.

vagrant@homestead:~/Code/forumio$ phpunit
PHPUnit 6.5.2 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 1.4 seconds, Memory: 8.00MB

OK (3 tests, 5 assertions)

Cool! It looks like we are passing. This means viewing a single thread in the browser should also work. Loading up a thread with the lucky number 7 for an id in the browser does work just great.
a user views single thread in browser


Adding Links Using a path() function

The final thing we can do in this tutorial is to add links to the index view so that when a user is browsing all threads, he or she can click a link to view a single thread. Let’s modify our index.blade.php file for threads like so.

That little path() method is a trick to create dynamic url’s automatically. If we try to load this in the browser right now, things are going to break. We need to add that function to our Thread model so that it works. Open up Thread.php and populate like so.

That will do the trick, and we can see that viewing all threads and then clicking to view more is working great.
browsing all and single threads in action


How To Create A Feature Test In Laravel Summary

This tutorial got us moving just a little bit further along with creating new features and making sure to have tests to support those features as we go. Great work in setting up the ability for a user to browse all threads and the associated test as well as creating the ability for a user to browse a single thread with the associated test as well.

|