【问题标题】:How to Disable Selected Middleware in Laravel Tests如何在 Laravel 测试中禁用选定的中间件
【发布时间】:2021-06-10 13:03:18
【问题描述】:

在运行phpunit 时,通常会出现来自身份验证和 CSRF 的错误。

在我们使用的TestCase中:

use WithoutMiddleware;

问题是当表单失败时,它通常会返回一个 Flash 消息和旧输入。我们已禁用所有中间件,因此我们无法访问 Input::old('username'); 或 flash 消息。

此外,我们对这个失败的表单的测试后返回:

Caused by
exception 'RuntimeException' with message 'Session store not set on request.

有没有办法启用会话中间件并禁用其他所有功能。

【问题讨论】:

标签: php laravel


【解决方案1】:

我发现最好的方法不是使用WithoutMiddleware trait,而是修改要禁用的中间件。例如,如果您想在测试中禁用 VerifyCsrfToken 中间件功能,您可以执行以下操作。

app/Http/Middleware/VerifyCsrfToken.php 中,添加一个handle 方法来检查APP_ENV 以进行测试。

public function handle($request, Closure $next)
{
    if (env('APP_ENV') === 'testing') {
        return $next($request);
    }

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

这将覆盖Illuminate\Foundation\Http\Middleware\VerifyCsrfToken 内部的handle 方法,完全禁用该功能。

【讨论】:

  • 不错的解决方案,易于阅读和理解。顺便说一句,env('APP_ENV') 可以替换为 app()->env 更好一点:)
  • 谢谢。如果有人希望覆盖 VerifyCSRF 句柄方法并且您得到 Argument 2 needs to be of type App\Http\Middleware\Closure,请检查此 answer
  • 您可以使用app()->runningUnitTests(),而不是直接检查env('APP_ENV')(它在内部将进行相同的评估,但如果未来环境值发生变化,它仍然可以工作)。
【解决方案2】:

Laravel >= 5.5

从 Laravel 5.5 开始,withoutMiddleware() 方法允许您指定要禁用的中间件,而不是全部禁用。因此,无需修改所有中间件以添加环境检查,您可以在测试中执行此操作:

$this->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class);

Laravel

如果您使用的是 Laravel

PHP >= 7

如果您使用的是 PHP7+,请将以下内容添加到您的 TestCase 类中,您将能够使用上述相同的方法调用。此功能使用 PHP7 中引入的匿名类。

/**
 * Disable middleware for the test.
 *
 * @param  string|array|null  $middleware
 * @return $this
 */
public function withoutMiddleware($middleware = null)
{
    if (is_null($middleware)) {
        $this->app->instance('middleware.disable', true);

        return $this;
    }

    foreach ((array) $middleware as $abstract) {
        $this->app->instance($abstract, new class {
            public function handle($request, $next)
            {
                return $next($request);
            }
        });
    }

    return $this;
}

PHP

如果您使用的是 PHP

在某处创建此类:

class FakeMiddleware
{
    public function handle($request, $next)
    {
        return $next($request);
    }
}

覆盖TestCase 中的withoutMiddleware() 方法并使用FakeMiddleware 类:

/**
 * Disable middleware for the test.
 *
 * @param  string|array|null  $middleware
 * @return $this
 */
public function withoutMiddleware($middleware = null)
{
    if (is_null($middleware)) {
        $this->app->instance('middleware.disable', true);

        return $this;
    }

    foreach ((array) $middleware as $abstract) {
        $this->app->instance($abstract, new FakeMiddleware());
    }

    return $this;
}

【讨论】:

  • 我刚刚浪费了 30 分钟,试图弄清楚为什么尽管我在测试中添加了 $this->withoutMiddleware('friendly-alias-name');,但该特定中间件仍在运行。原来你必须使用中间件类名而不是友好别名。
【解决方案3】:

您可以在测试中使用 trait:

使用 Illuminate\Foundation\Testing\WithoutMiddleware;

Laravel >= 5.7

【讨论】:

    【解决方案4】:

    我可能会迟到,但我已经弄清楚了:

    $this->withoutMiddleware([
       'email-verified', //alias does NOT work
       EnsureEmailIsVerified::class //Qualified class name DOES WORK
    ]);
    

    【讨论】:

      【解决方案5】:

      以下内容对我有用:

      use WithoutMiddleware;
      
      public function setUp(): void
      {
          parent::setUp();
          $this->withoutMiddleware();
      }
      
      【解决方案6】:
      The withoutMiddleware method can only remove route middleware and does not apply to global middleware.
      

      来自https://laravel.com/docs/8.x/middleware

      【讨论】:

        猜你喜欢
        • 2013-08-04
        • 1970-01-01
        • 2018-09-05
        • 2015-09-22
        • 2012-10-25
        • 2016-12-31
        • 2012-07-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多