netdjw
netdjw

Reputation: 6007

Laravel testing - 429 Too Many Requests

As I move forward in my Laravel project I have several tests for controllers and now I'm facing with this issue.

Some of my tests are failing with this message:

Expected response status code [200] but received 429.
Failed asserting that 200 is identical to 429.

I tried to solve with these methods:

  1. Add withoutMiddleware() to TestCase.php:
public function setUp(): void
{
    parent::setUp();

    $this->withoutMiddleware(
        ThrottleRequests::class
    );
}
  1. Add REQUESTS_PER_MINUTE to phpunit.xml:
<phpunit>
  <php>
    ...
    <server name="REQUESTS_PER_MINUTE" value="500"/>
  </php>
</phpunit>
  1. Change my dockerized nginx config for this:
server {
    location ~ \.php$ {
        limit_req zone=one burst=5;
    }
}
limit_req_zone  $binary_remote_addr  zone=one:10m   rate=100r/s;

Neither solution helped.

I don't want to change the Laravel's throttle settings only because of testing. I think here need to be a valid solution for this without changing the framework's settings.

Any suggestion how can I solve this issue?

Upvotes: 3

Views: 10605

Answers (4)

Epok98
Epok98

Reputation: 109

So today I ran into the same issue on laravel 10 and found this amazing answer but for some reason it was not top result for me.

answer by @Mostafa Bahri https://stackoverflow.com/a/52369024/17809957use

Illuminate\Routing\Middleware\ThrottleRequests;

class YourTest extends TestCase 
{

    protected function setUp()
    {
        parent::setUp();
        $this->withoutMiddleware(
            ThrottleRequests::class
        );
    }
    ...
}

Upvotes: 3

Numa
Numa

Reputation: 31

I was currently facing this same issue testing with Laravel 9.

I solved it adding inside the 'configureRateLimiting()' method in 'RouteServiceProvider.php' the following code:

RateLimiter::for('test', function (Request $request) {
    return Limit::perMinute(XX)->by($request->ip());
});

Replace the 'XX' with the max amount of API requests per minute you want to allow during testing.

After that run:

php artisan config:clear

And:

php artisan cache:clear

I hope this helps!

Upvotes: 3

Andrew
Andrew

Reputation: 46

Frank's solution works but makes not possible to use named limiters. Code below passes correct arguments list and allow to detect named limiters

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis;

class ThrottleRequests extends ThrottleRequestsWithRedis
{
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
    {
        if (app()->environment('production')) {
            return parent::handle(...func_get_args());
        }

        return $next($request);
    }
}

Upvotes: 1

Frank
Frank

Reputation: 291

My solution to this, although not the most elegant was to replace the ThrottleMiddleware with my own and checking the env for testing, effectively disabling laravel's throttling for for phpunit. :

<?php

namespace App\Http\Middleware;

use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis;
use Closure;

class ThrottleRequests extends ThrottleRequestsWithRedis
{
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '')
    {
        if (config('app.env') === 'testing') {
            return $next($request);
        }

        return parent::handle($request, $next, $maxAttempts, $decayMinutes, $prefix);
    }
}

You will then need to update your kernel.php to use your new class e.g.

protected $routeMiddleware = [
...
'throttle' => \App\Http\Middleware\ThrottleRequests::class,
...
];

Upvotes: 4

Related Questions