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

问题描述 投票:0回答:6

我想测试删除方法,但我没有从 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 版本:5.5

感谢您的帮助!

控制器构造函数:

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

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

控制器方法:

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

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

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

类别访问中间件:

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

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

    return $next($request);
}

类别型号:

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

事件监听器

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 删除测试:

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');
}
laravel phpunit
6个回答
54
投票

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

php artisan config:clear
来解决此问题。

说明:之所以可以解决该问题,是因为 PHPUnit 将使用缓存的配置值,而不是测试环境中定义的变量。因此,

APP_ENV
未设置为测试,并且
VerifyCsrfTokenMiddleware
将抛出
TokenMismatchException
(状态代码 419)。

APP_ENV
设置为测试时,不会抛出此异常,因为
handle
VerifyCsrfTokenMiddleware
方法会检查您是否正在使用
$this->runningUnitTests()
运行单元测试。

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

TestCase.php
:

中手动清除缓存
use Illuminate\Support\Facades\Artisan; 

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

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

在这篇博客文章Laravel文档中阅读有关配置缓存的更多信息。


17
投票

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

use Illuminate\Foundation\Testing\WithoutMiddleware;

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

    //tests here
}

如果您想仅为一项特定测试用途禁用它们:

$this->withoutMiddleware();

4
投票

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

中间件带有内置代码,可以检测它是否在测试中使用。这项检查会检查两件事:

  • 我是通过命令行运行的吗
  • 我是否在
    testing
  • 的环境类型中运行

默认情况下,正确设置软件会导致运行 PHP 单元时两个标志都为 true。然而,最有可能的罪魁祸首是你的

APP_ENV
中的值。导致此错误的常见方式包括:

  • phpunit.xml
    文件配置错误。它应该包含
    <server name="APP_ENV" value="testing" />
  • APP_ENV
    中设置显式值的 shell 会话会覆盖此值
  • APP_ENV
    中设置了显式值的 Docker/docker-compose/kubernetes 会话。如果可能的话,了解通过 .env 和/或 phpunit.xml 文件设置此值可能会更好。或者确保构建/测试过程设置该值。

这个也难倒了我,我不相信我需要使用

WithoutMiddleware
,因为我没有用于不同的项目,但事实证明我在命令行上尝试了一些东西并覆盖了
APP_ENV
重击。


4
投票

这是确切的解决方案:

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);
    }

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

APP_ENV=testing

0
投票

修改文件

app/Http/Middleware/VerifyCsrfToken.php
添加:

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

    return $next($request);
}

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


0
投票

这是根据我的经验,我将程序切换为静态

php artisan config:cache

php artisan route:cache

这导致csrf运行,所以我将其更改为原始模式

php artisan config:clear

php artisan route:clear
© www.soinside.com 2019 - 2024. All rights reserved.