Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Organizm238's avatar

Catching abort() exception code with Laravel TestCase

Hi! I have simple middleware and i want to test it.

Middleware:

public function handle($request, Closure $next)
    {
        $user = $request->user();
        if ($user && $user->isAdmin()) {
            return $next($request);
        }

        abort(403, 'You are not a site administrator!');
    }

My test (it works):

public function testMiddlewareThrowsErrorForNonAdminUser()
    {
        $employer = factory(User::class)->create(['role' => User::EMPLOYER_ROLE]);
        $request = new Illuminate\Http\Request();
        $request->setUserResolver(function() use ($employer) {
            return $employer;
        });
        $this->expectExceptionMessage('You are not a site administrator!');
        $this->handleRequestWithMustBeAdminMiddleware($request);
    }

protected function handleRequestWithMustBeAdminMiddleware($request) {
        $middleware = new \App\Http\Middleware\MustBeAdmin();
        $middleware->handle($request, function() {});
    }

I'm sure i am missing smth about expectExceptionCode() function. Here i am trying to work with it:

public function testMiddlewareThrowsErrorForNonAdminUser()
    {
        $employer = factory(User::class)->create(['role' => User::EMPLOYER_ROLE]);
        $request = new Illuminate\Http\Request();
        $request->setUserResolver(function() use ($employer) {
            return $employer;
        });
        $this->expectExceptionCode(403);
        $this->handleRequestWithMustBeAdminMiddleware($request);
    }

And i get in my console:

1) MustBeAdminTest::testMiddlewareThrowsErrorForNonAdminUser
Failed asserting that 0 is equal to expected exception code 403.

Laravel's abort() function for some reason returns 0 code. Why is it so ?

0 likes
5 replies
orange_adrenalin's avatar

I have the same problem :( I can't catch error after abort by code, because code is always 0

orange_adrenalin's avatar

I find problem!

/**
     * Throw an HttpException with the given data.
     *
     * @param  int     $code
     * @param  string  $message
     * @param  array   $headers
     * @return void
     *
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException
     */
    public function abort($code, $message = '', array $headers = [])
    {
        if ($code == 404) {
            throw new NotFoundHttpException($message);
        }

        throw new HttpException($code, $message, null, $headers);
    }

if we fire abort(404) component doesn't set code to NotFoundHttpException in Illuminate\Foundation\Application.php

peterjohnmcfarlane@gmail.com's avatar
Level 1

The answer lies in the Symfony\Component\HttpKernel\Exception\HttpException that is thrown. Look at it's constructor, the default $code = 0.

public function __construct($statusCode, $message = null, \Exception $previous = null, array $headers = array(), $code = 0)

Notice that $statusCode and the Exception $code are two different things.

If you must test the exception code, you could always rewrite the test like this

public function testMiddlewareThrowsErrorForNonAdminUser()
{
    $employer = factory(User::class)->create(['role' => User::EMPLOYER_ROLE]);
    $request = new Illuminate\Http\Request();
    $request->setUserResolver(function() use ($employer) {
        return $employer;
    });
    try {
        $this->handleRequestWithMustBeAdminMiddleware($request);
    } catch (\Throwable $e) {
    }
    $this->assertEquals(
        new HttpException(403, 'You are not a site administrator!'),
        $e
    );
}

(Notice how the assertion is outside the catch, this will mean that if try doesn't throw an exception the test will still fail because $e is not defined.)

3 likes

Please or to participate in this conversation.