3

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?

netdjw
  • 5,419
  • 21
  • 88
  • 162
  • Can you share the code that is giving you problems ? What test ? – matiaslauriti Nov 12 '21 at 00:13
  • Mostly controller tests. Get, pos5, put and delete http requests. Nothing special. – netdjw Nov 12 '21 at 06:05
  • Did you modify how the Middleware works? What is your `phpunit.xml`? (share it without important keys please). Have you changed the behaviour of the class `TestCase` or similar (did you modify anything about the Laravel TestCase class?) – matiaslauriti Nov 12 '21 at 18:33
  • @matiaslauriti I didn't modify the Middleware. I didn't modify the `phpunit.xml`, only add the line what I wrote. The `TestCase` is modified a several functions, like `mockSuperUser()`, `mockUnauthorizedUser()`, `setHeaders()` and some similar of these. These functions are not affected on behavior of TestCase, they are just "global" functions for testing. In the TestCase `setUp()` I run this two things: `$this->seed();` and then `$this->withoutMiddleware(ThrottleRequests::class);`. That's all. – netdjw Nov 13 '21 at 16:09

3 Answers3

2

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,
...
];
Frank
  • 243
  • 1
  • 2
  • 14
2

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!

Numa
  • 21
  • 2
1

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);
    }
}
Andrew
  • 46
  • 3