PHPUnit:预期状态码 200 但使用 Laravel 收到 419
Posted
技术标签:
【中文标题】PHPUnit:预期状态码 200 但使用 Laravel 收到 419【英文标题】:PHPUnit: Expected status code 200 but received 419 with Laravel 【发布时间】:2018-03-01 17:38:57 【问题描述】:我想测试删除方法,但我没有从 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');
categoryAccess 中间件:
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');
【问题讨论】:
这是一个身份验证问题,试试$this->withoutMiddleware();
看看会不会OK!!
您好,谢谢,我将其添加到方法中并再次运行测试,我现在收到此消息:预期状态代码 200 但收到 302。
这次试试 PHPUnit 类中的 use WithoutMiddleware;
,别忘了导入它 use Illuminate\Foundation\Testing\WithoutMiddleware;
谢谢@Maraboc $this->withoutMiddleware();作品!问题是这个测试应该期待状态码 302 我通过阅读来自 here 的答案发现的。
很高兴知道 ;)
【参考方案1】:
解决方案:当您缓存配置文件时,您可以通过运行php artisan config:clear
来解决此问题。
说明:这可以解决问题的原因是 PHPUnit 将使用缓存的配置值而不是在您的测试环境中定义的变量。因此,APP_ENV
未设置为测试,VerifyCsrfTokenMiddleware
将抛出 TokenMismatchException
(状态代码 419)。
当APP_ENV
设置为测试时,它不会抛出此异常,因为VerifyCsrfTokenMiddleware
的handle
方法会检查您是否使用$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的示例
在此blog post 或Laravel documentation 中阅读有关配置缓存的更多信息。
【讨论】:
这对我也有用,但为什么这能解决问题? @DarrenFindlay 我已经添加了一些解释。【参考方案2】:这是确切的解决方案:
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
【讨论】:
【参考方案3】:这里的消息确实和CSRF中间件有关。但是有一个比禁用中间件更好的方法来解决这个问题。
中间件带有内置代码,用于检测它是否在测试中使用。此检查查找 2 件事:
我是通过命令行运行的吗 我是否在testing
的环境类型中运行
默认,正确设置软件会导致在运行 PHP 单元时两个标志都为真。但是,最可能的罪魁祸首是您的APP_ENV
中的值。导致此错误的常见方式包括:
phpunit.xml
文件配置错误。它应该包含<server name="APP_ENV" value="testing" />
在 APP_ENV
中设置了显式值的 shell 会话,该值会覆盖此值
在APP_ENV
中设置了显式值的 Docker/docker-compose/kubernetes 会话。如果可能的话,查看通过 .env 和/或 phpunit.xml 文件设置此值可能会更好。或者确保构建/测试过程设置值。
这也难倒了我,我不相信我需要使用WithoutMiddleware
,因为我没有用于其他项目,但事实证明我已经在命令行上尝试了一些东西并覆盖了@987654328 @ 在 bash 中。
【讨论】:
【参考方案4】:修改文件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
【讨论】:
【参考方案5】:有时在测试中您需要禁用中间件才能继续:
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ClassTest extends TestCase
use WithoutMiddleware; // use this trait
//tests here
如果您只想针对一项特定的测试用途禁用它们:
$this->withoutMiddleware();
【讨论】:
这有效,除非中间件实际上是您的测试的一部分。以上是关于PHPUnit:预期状态码 200 但使用 Laravel 收到 419的主要内容,如果未能解决你的问题,请参考以下文章
NSLocalizedDescription=(200-299)中的预期状态码,得到 422
NSLocalizedDescription=(200-299) 中的预期状态码,得到 400
AJAX请求服务器,响应状态码为200,但调用error函数
RestKit .20 RKRequestDescriptor postObject - (400-499) 中的预期状态代码,得到 200