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

laravelcloud logo
Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Visit Laravel Cloud

The latest

View all →
CPX: The Composer Package Executor for PHP image

CPX: The Composer Package Executor for PHP

Read article
Laravel AI SDK Adds Human-in-the-Loop Tool Approval image

Laravel AI SDK Adds Human-in-the-Loop Tool Approval

Read article
Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals image

Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals

Read article
Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs image

Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs

Read article
Blade Formatting in Laravel Pint image

Blade Formatting in Laravel Pint

Read article
Inertia DevTools Is Now on the Chrome Web Store image

Inertia DevTools Is Now on the Chrome Web Store

Read article