Laravel Tutorials

Asserting Exceptions in Laravel Tests

Published
Asserting Exceptions in Laravel Tests image

Laravel's recent release of Laravel 11.4 introduced the Exceptions facade, which adds conveniences around asserting exceptions in Laravel's exception handler. Before this release, I would typically use the $this->withoutExceptionHandling() to assert that a specific exception happened during an HTTP test:

use App\Exceptions\WelcomeException;
 
$this->withoutExceptionHandling();
 
try {
$this->get('/');
} catch (WelcomeException $e) {
$this->assertEquals('Woops, there was an issue with your request!', $e->getMessage());
 
return;
}
 
$this->fail(sprintf('The expected "%s" exception was not thrown.', WelcomeException::class));

When you expect a request to not throw any exceptions, using withoutExceptionHandling cuts out the middleman when you're debugging why an error is happening when you don't expect it. The above code is tedious to write, because it manually captures the exception, makes assertions about the exception, and calls return to avoid the manual $this->fail() call. The manual failure will catch situations when the test doesn't throw an exception when expected.

If $this->fail() is called in the above scenario, here's what the output would look like:

$ phpunit
 
There was 1 failure:
 
1) Tests\Feature\ExampleTest::test_the_application_returns_a_successful_response
The expected "App\Exceptions\WelcomeException" exception was not thrown.
 
/app/tests/Feature/ExampleTest.php:33

Laravel's Exceptions Facade

Let's look at how the new Exceptions facade can simplify our test; the first example, rewritten, would look as follows:

use Illuminate\Support\Facades\Exceptions;
 
Exceptions::fake();
 
$this->get('/');
 
Exceptions::assertReported(function (WelcomeException $e): bool {
return $e->getMessage() === "Woops, there was an issue with your request!";
});

Using the Exceptions facade gives us the bonus of not having to capture an exception to assert things manually. Said another way, the test can keep Laravel's exception handler in place but still be able to assert exceptions that happened during a request.

If we want to be sure that a test doesn't throw a specific exception or doesn't throw any exceptions, period, the new facade has our back:

Exceptions::assertNotReported(WelcomeException::class);
 
Exceptions::assertNothingReported();

If the exception handler does not report the WelcomeException, the test output would give us a nicely formatted message:

$ phpunit
 
There was 1 failure:
 
1) Tests\Feature\ExampleTest::test_the_application_returns_a_successful_response
The expected [App\Exceptions\WelcomeException] exception was not reported.

While there may be times when you don't want to fake Laravel's exception handler, when testing edge cases, the new Exceptions facade is tremendously helpful and cleans up our code:

Exceptions::assertReported(WelcomeException::class);
Exceptions::assertReportedCount($count);
Exceptions::assertNotReported(WelcomeException::class);
Exceptions::assertNothingReported();
Exceptions::throwFirstReported();

To learn more about the Exceptions facade, check out Laravel’s documentation.

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Sponsored

acquaintsoft logo
Acquaint Softtech

Hire Laravel developers with AI expertise at $20/hr. Get started in 48 hours.

Visit Acquaint Softtech

The latest

View all →
Laravel Auditor Audits Your App With Your Own AI Agent image

Laravel Auditor Audits Your App With Your Own AI Agent

Read article
A simple form builder that stays out of your way image

A simple form builder that stays out of your way

Read article
Laravel AI: Trace Agent Runs With Lifecycle Events image

Laravel AI: Trace Agent Runs With Lifecycle Events

Read article
Laravel AI: Get Raw HTTP Responses and Rate Limits image

Laravel AI: Get Raw HTTP Responses and Rate Limits

Read article
Agent Run Observability in Laravel AI SDK 0.11 image

Agent Run Observability in Laravel AI SDK 0.11

Read article
Debounced Queued Event Listeners in Laravel image

Debounced Queued Event Listeners in Laravel

Read article