How To Toggle Exception Handling

How To Toggle Exception Handling

In this tutorial we’ll continue to build out our application and associated tests. First off we’ll dry up our routes file by making use of a route resource instead of manually creating every single route for each http verb. We’ll then move in to adding a form for authenticated users to submit a new thread. We’ll also update some middleware and update our tests to support these new features. Finally, we’ll focus on the new feature of Laravel which allows you to Toggle Exception Handling in your tests which is sometimes needed.

Clean Up Routes File With Route::resource

We can start off with the idea of using Route::resource in our routes file. So far, we have been sticking to using only the restful verbs in our controllers and routes file. We are starting to see a bit of duplication in our routes file. We can reduce this by simply using Route::resource. In the following snippet, notice that we can get rid of 4 lines of code with 1. We’ll leave them commented out here to show that having 1 Route::resource is the equivalent of have all 4 of these routes manually set up.

We can even run all of our tests, and they still pass which is fantastic.

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

............                                                      12 / 12 (100%)

Time: 1.99 seconds, Memory: 10.00MB

OK (12 tests, 15 assertions)

Update ThreadsController@create To Display A Form

In order for a logged in user to submit a thread, we need to display a form to them. We can update our create method in the ThreadsController to support this here.

Of course we also need to create the actual view file in resources/views/threads/create.blade.php. We can add the following markup to make it work.

When we visit we are now seeing a pretty good looking form.
form to submit new thread

Don’t be shy, go ahead and fill out the form title and body, then click on Publish.
publishing a new thread

Sweet! On Publishing the thread, we get redirected right to that thread page and we can view it. We could also post a reply if we like.
thread publishing worked great

The thread reply is now in place as well.
a new reply is in place

Update Middleware To Protect This Route

If a guest browses the /threads/create endpoint, a form is still displayed. We don’t even want to display a form to submit a new thread for non logged in users. Let’s correct that by updating the middleware we set up earlier.

Create New Test Guest Redirect of threads/create

If you try to load up threads/create as a guest, you will in fact be redirected to the login page thanks to our new middleware above. We do not yet have an actual test for this however. We can add one in the CreateThreadsTest class now.

If we run the test, we do get a bit of a problem.

vagrant@homestead:~/Code/forumio$ phpunit --filter test_guest_can_not_see_thread_create_form
PHPUnit 6.5.4 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.14 seconds, Memory: 8.00MB

There was 1 error:

1) TestsFeatureCreateThreadsTest::test_guest_can_not_see_thread_create_form
IlluminateAuthAuthenticationException: Unauthenticated.

This highlights something you might sometimes run into in testing. There are times when you want the test to throw an exception, and others when you may not. It turns out however that this is now baked in to the 5.5 version via the $this->withoutExceptionHandling() method. So we will need to go back to our Handler.php file and remove the line which has if(app()->environment() === ‘testing’) throw $exception;

So now if we update our test like the following it should pass.

I wonder what will happen if we run all tests? Remember, we had previously set up our Handler to always throw the exception in testing. We no longer have that so we might see some failures.

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

F..F.........                                                     13 / 13 (100%)

Time: 1.69 seconds, Memory: 10.00MB

There were 2 failures:

1) TestsFeatureCreateThreadsTest::test_guest_can_not_create_threads
Failed asserting that exception of type "IlluminateAuthAuthenticationException" is thrown.

2) TestsFeatureParticipateInForumTest::test_unauthenticated_users_can_not_add_replies
Failed asserting that exception of type "IlluminateAuthAuthenticationException" is thrown.

Tests: 13, Assertions: 17, Failures: 2.

Ah ha – we do see some failures. It looks like we will need to update the test_guest_can_not_create_threads() and test_unauthenticated_users_can_not_add_replies() tests to include a call to $this->withoutExceptionHandling() and we should be back to passing. Let’s try it out.

Fix for test_guest_can_not_create_threads()

Fix for test_unauthenticated_users_can_not_add_replies()

Now we can see everything is passing again.

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

.............                                                     13 / 13 (100%)

Time: 1.68 seconds, Memory: 10.00MB

OK (13 tests, 17 assertions)

How To Toggle Exception Handling Summary

Sometimes when you’re writing tests, an exception is thrown during the test that inadvertantly causes the test to fail when it should have passed. In plain PHP you can use try catch flow control for errors. A new feature in the latest version of Laravel now allows you to selectively disable exception handling for special cases. Prior to this Jeffrey Way and Adam Wathan gave us a workaround with some custom code we could populate our TestCase.php with. Taylor has since moved this code right into the framework. By default the framework handles exceptions and converts them into the correct response when testing. Again however, you may not want to see the converted response, but the full exception. In this case, you can make use of that call to $this->withoutExceptionHandling() to get the desired result.