Summer Sale! All accounts are 50% off this week.

thomthom's avatar

Why are tests are slow when testing HTTP 410 routes?

Laravel 10.

I got some routes that are now obsolete, which I setup up as:

    Route::get('example', function () {
        App::abort(410);
    });

My test for this:

public function test_example(): void
    {
        $this->get('example')
                ->assertGone();
    }

These tests takes 400-500ms. Compared to 5-30ms for other "normal" routes.

Any ideas why?

0 likes
7 replies
LaryAI's avatar
Level 58

The reason why the tests for HTTP 410 routes are slower compared to other "normal" routes is because Laravel's default behavior is to handle exceptions by rendering an error view. In this case, when the route returns a 410 status code, Laravel will render the error view, which adds extra processing time.

To improve the speed of the tests for HTTP 410 routes, you can modify the exception handler to return a response directly instead of rendering a view. Here's how you can do it:

  1. Open the app/Exceptions/Handler.php file.

  2. Locate the render method.

  3. Add the following code at the beginning of the method:

if ($exception instanceof \Symfony\Component\HttpKernel\Exception\GoneHttpException) {
    return response('', 410);
}

This code checks if the exception is an instance of GoneHttpException (which is thrown when you use App::abort(410)), and if so, it returns a response with a 410 status code and an empty body.

  1. Save the file.

With this modification, the exception handler will return a response directly for HTTP 410 routes, eliminating the need to render an error view and improving the speed of the tests.

Please note that modifying the exception handler affects the behavior of your application globally. If you want to apply this change only for testing purposes, you can conditionally apply the modification based on the environment. For example:

if (app()->environment('testing')) {
    if ($exception instanceof \Symfony\Component\HttpKernel\Exception\GoneHttpException) {
        return response('', 410);
    }
}

This way, the modification will only be applied when running tests.

1 like
thomthom's avatar

@LaryAI This almost worked. I wasn't actually getting a GoneHttpException from App::abort(410), but this worked:

    public function register(): void
    {
        $this->renderable(function (HttpException $e, $request) {
            if (app()->environment('testing')) {
                // This speeds up the tests for the 410 routes by avoiding the
                // default callstack rendering.
                if ($e->getStatusCode() == 410) {
                    return response('410 Gone', 410);
                }
            }
        });
    }
Tray2's avatar

Why do you even have those kinds of tests? Just let laravel hit you with a 404 instead.

thomthom's avatar

@Tray2 I've always tried to use the best matching HTTP code. And in any case I wanted tests to ensure that the routes that used to exists now really are gone.

thomthom's avatar

I see that is faster in the tests. But what makes that HTTP code faster?

This might be a local dev issue. (But still something I'd like to better understand.) I realized that then I use App::abort(410); and view on localhost I get and debug error view with callstack.

Tray2's avatar

@thomthom 404 is handled by the Laravel exception handler, I'm guessing the 410 isn't, and the error page with the stack trace might take some time to generate.

Please or to participate in this conversation.