PHPUnit:预期状态代码 200,但 Laravel 收到 419

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46325790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 16:40:48  来源:igfitidea点击:

PHPUnit: Expected status code 200 but received 419 with Laravel

laravelphpunit

提问by baselwebdev

I want to test the delete method but I am not getting the expected results from PHPUnit. I receive this message when running the test:

我想测试删除方法,但我没有从 PHPUnit 获得预期的结果。我在运行测试时收到此消息:

 Expected status code 200 but received 419. Failed asserting that false is true.
 /vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:77
 /tests/Unit/CategoriesControllerTest.php:70

Laravel version: 5.5

Laravel 版本:5.5

Thank you for any help!

感谢您的任何帮助!

Controller constructor:

控制器构造函数:

public function __construct()
{
    $this->middleware('auth');

    $this->middleware('categoryAccess')->except([
        'index',
        'create'
    ]);
}

Controller method:

控制器方法:

public function destroy($categoryId)
{
    Category::destroy($categoryId);

    session()->flash('alert-success', 'Category was successfully deleted.');

    return redirect()->action('CategoriesController@index');
}

categoryAccess middleware:

类别访问中间件:

public function handle($request, Closure $next)
{
    $category = Category::find($request->id);

    if (!($category->user_id == Auth::id())) {
        abort(404);
    }

    return $next($request);
}

Category model:

类别型号:

protected $dispatchesEvents = [
    'deleted' => CategoryDeleted::class,
];

Event listener

事件监听器

public function handle(ExpensesUpdated $event)
{
    $category_id = $event->expense->category_id;

    if (Category::find($category_id)) {
        $costs = Category::find($category_id)->expense->sum('cost');

        $category = Category::find($category_id);

        $category->total = $costs;

        $category->save();
    }
}

PHPUnit delete test:

PHPUnit删除测试:

use RefreshDatabase;

protected $user;

public function setUp()
{
   parent::setUp();
   $this->user = factory(User::class)->create();
   $this->actingAs($this->user);
}

/** @test */
public function user_can_destroy()
{
    $category = factory(Category::class)->create([
        'user_id' => $this->user->id
    ]);

    $response = $this->delete('/category/' . $category->id);

    $response->assertStatus(200);

    $response->assertViewIs('category.index');
}

回答by piscator

Solution: When you cached your configuration files you can resolve this issue by running php artisan config:clear.

解决方案:当您缓存配置文件时,您可以通过运行php artisan config:clear.

Explanation: The reason why this can resolve the issue is that PHPUnit will use the cached configuration values instead of the variables defined in your testing environment. As a result, the APP_ENVis not set to testing, and the VerifyCsrfTokenMiddlewarewill throw a TokenMismatchException(Status code 419).

说明:这可以解决问题的原因是 PHPUnit 将使用缓存的配置值而不是在您的测试环境中定义的变量。结果,APP_ENV未设置为测试,并且VerifyCsrfTokenMiddleware将抛出TokenMismatchException(状态代码 419)。

It won't throw this exception when the APP_ENVis set to testing since the handlemethod of VerifyCsrfTokenMiddlewarechecks if you are running unit tests with $this->runningUnitTests().

当它不会抛出此异常APP_ENV设定为自测试handle的方法VerifyCsrfTokenMiddleware检查,如果您正在使用运行单元测试$this->runningUnitTests()

It is recommended not to cache your configuration in your development environment. When you need to cache your configuration in the environment where you are also running unit tests you could clear your cache manually in your TestCase.php:

建议不要在您的开发环境中缓存您的配置。当您需要在同时运行单元测试的环境中缓存您的配置时,您可以在您的TestCase.php.

use Illuminate\Support\Facades\Artisan; 

public function createApplication()
{
    ....
    Artisan::call('config:clear')
    ....
}

Example based on https://github.com/laravel/framework/issues/13374#issuecomment-239600163

基于https://github.com/laravel/framework/issues/13374#issuecomment-239600163 的示例

回答by Maraboc

Sometimes in testing you will need to disable middlewares to proceed :

有时在测试中,您需要禁用中间件才能继续:

use Illuminate\Foundation\Testing\WithoutMiddleware;

class ClassTest extends TestCase
{
    use WithoutMiddleware; // use this trait

    //tests here
}

and if you want to disable them just for one specific test use :

如果您只想为一个特定的测试使用禁用它们:

$this->withoutMiddleware();

回答by Jouva Moufette

The message here is indeed related to the CSRF middleware. But there is a much better way of attacking this problem than disabling the middleware.

这里的消息确实与CSRF中间件有关。但是有一个比禁用中间件更好的方法来解决这个问题。

The middleware comes with code built-in that detects if it is being used in a test. This check looks for 2 things:

中间件带有内置代码,用于检测它是否正在测试中使用。此检查查找两件事:

  • Am I being ran via a command line
  • Am I being ran in an environment type of testing
  • 我是通过命令行运行的吗
  • 我是否在环境类型中运行 testing

Default, proper setup of the software correctly causes both flags to be true when running PHP unit. However, the most likely culprit is the value in your APP_ENV. Common ways for this to to be incorrect include:

默认情况下,正确设置软件会导致在运行 PHP 单元时这两个标志都为真。但是,最有可能的罪魁祸首是您的APP_ENV. 导致此错误的常见方法包括:

  • Misconfigured phpunit.xmlfile. It should contain <server name="APP_ENV" value="testing" />
  • A shell session that has an explicit value set in APP_ENVthat overrides this value
  • A Docker/docker-compose/kubernetes session that has an explicit value set in APP_ENV. Seeing about getting this value set via the .env and/or phpunit.xml files is perhaps better if possible. Or ensuring the build/test process sets the value.
  • 错误配置的phpunit.xml文件。它应该包含<server name="APP_ENV" value="testing" />
  • APP_ENV其中设置了显式值并覆盖此值的shell 会话
  • 一个 Docker/docker-compose/kubernetes 会话,在APP_ENV. 如果可能,查看通过 .env 和/或 phpunit.xml 文件设置此值可能会更好。或者确保构建/测试过程设置该值。

This one stumped me as well and I was not convinced that I would need the use of WithoutMiddlewaresince I did not for a different project, but it turned out I had experimented with something on the command line and overrode APP_ENVin bash.

这个也难倒了我,我不相信我需要使用 ,WithoutMiddleware因为我没有用于不同的项目,但结果证明我已经在命令行上尝试了一些东西并APP_ENV在 bash 中覆盖。

回答by Farid shahidi

This is the exact solution:

这是确切的解决方案:

Laravel environment will set after bootstraping application, so you cant change it from appServiceProvider or another source. for fix this error you need to add this function to App\Http\Middleware\VerifyCsrfToken

Laravel 环境将在引导应用程序后设置,因此您无法从 appServiceProvider 或其他来源更改它。要修复此错误,您需要将此函数添加到 App\Http\Middleware\VerifyCsrfToken

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

        return $next($request);
    }

you need to use env('APP_ENV') that is set in .env.testing file with

您需要使用 .env.testing 文件中设置的 env('APP_ENV')

APP_ENV=testing

回答by Hussam

modify the file app/Http/Middleware/VerifyCsrfToken.phpby adding:

app/Http/Middleware/VerifyCsrfToken.php通过添加以下内容来修改文件:

public function handle($request, \Closure $next)
{
    if ('testing' !== app()->environment())
    {
        return parent::handle($request, $next);
    }

    return $next($request);
}

source: https://laracasts.com/discuss/channels/testing/trouble-testing-http-verbs-with-phpunit-in-laravel/replies/29878

来源:https: //laracasts.com/discuss/channels/testing/trouble-testing-http-verbs-with-phpunit-in-laravel/replies/29878