Laravel和Codeception - 测试在PUT表单上失败 [英] Laravel and Codeception - test fails on PUT forms
问题描述
这显示了 artisan route:list
命令输出:
+ -------- + ------------ -------------------- + ----------------------------- ------------------------------ + ------------------- ------------------- + ------------------------------ -------------------------------------------------- + ------------ +
|域|方法| URI |名称|操作|中间件|
+ -------- + -------------------------------- + --- -------------------------------------------------- ------ + -------------------------------------- + ---- -------------------------------------------------- -------------------------- + ------------ +
...
| | PUT |用户/ {users} | users.update | App \Http\Controllers\Users\UsersController @ update | auth |
它可以在我的网页浏览器上正常运行,但是当我尝试使用代码运行测试时,形式我得到一个方法不允许异常和测试失败。
我想知道为什么会发生这种情况,它似乎是由codeception提出的请求。该请求使用POST而不是PUT方法来阻止Laravel匹配路由。
HTML表单不支持PUT方法,所以Laravel Form
helper类创建如下表单:
< form method =POSTaction =https ://myapp.dev/users/172accept-charset =UTF-8>
< input name =_ methodvalue =PUTtype =hidden>
...
然而,它似乎并没有读取 _method
value。
我该如何解决这个问题?深入研究代码,我发现测试不会覆盖请求方法,因为 Request 类中有一个常量
Request :: $ httpMethodParameterOverride
。
/ **
*获取请求预期方法。
*
*如果设置了X-HTTP-Method-Override标头,并且该方法是POST,则
*用于确定实际预期的HTTP方法。
*
*只有在调用了enableHttpMethodParameterOverride()时,_method请求参数才可用于确定HTTP方法
*。
*
*该方法始终是大写字符串。
*
* @return string请求方法
*
* @api
*
* @get getRealMethod()
* /
public function getMethod()
{
if(null === $ this-> method){
$ this-> method = strtoupper($ this-> server - > get('REQUEST_METHOD','GET'));
if('POST'=== $ this-> method){
if($ method = $ this-> headers-> get('X-HTTP-METHOD -OVERRIDE')){
$ this-> method = strtoupper($ method);
} elseif(self :: $ httpMethodParameterOverride){
$ this-> method = strtoupper($ this-> request-> get('_ method',$ this-> query-> ; get('_ method','POST')));
}
}
}
返回$ this->方法;
}
以前的常量值应该是 true
,但是当我运行测试时,它的值是 false
。
我找到了一个解决方案,但我认为这不是写它的正确地方。
我在 Connector \Laravel5
类中添加了一行简单的代码。
public function __construct($ module)
{
$ this-> module = $ module;
$ this-> initialize();
$ components = parse_url($ this-> app ['config'] - > get('app.url','http:// localhost'));
$ host = isset($ components ['host'])? $ components ['host']:'localhost';
parent :: __ construct($ this-> app,['HTTP_HOST'=> $ host]);
//父构造函数默认为不重定向
$ this-> followRedirects(true);
//新增来解决重写请求方法的问题
Request :: enableHttpMethodParameterOverride();
}
这解决了我的问题。
I have a resource controller in laravel to manage my users. This creates a route to update users info that takes a request with HTTP PUT method.
This shows artisan route:list
command output:
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
...
| | PUT | users/{users} | users.update | App\Http\Controllers\Users\UsersController@update | auth |
It works correctly on my web browser but when I try to run a test with codeception and I submit the form I get a method not allowed exception and the test fails.
I tried to see why this is happening and it seems to be the request made by codeception. That request is made with POST instead of PUT method preventing Laravel from matching the route.
HTML forms doesn't suport PUT methods so Laravel Form
helper class creates the form as follows:
<form method="POST" action="https://myapp.dev/users/172" accept-charset="UTF-8">
<input name="_method" value="PUT" type="hidden">
...
However, it seems that codeception is not reading the _method
value.
How can I fix this?
EDIT: Looking deeply on the code I found that test don't override the request method beacause of a constant in th Request
class called Request::$httpMethodParameterOverride
.
/**
* Gets the request "intended" method.
*
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
* then it is used to determine the "real" intended HTTP method.
*
* The _method request parameter can also be used to determine the HTTP method,
* but only if enableHttpMethodParameterOverride() has been called.
*
* The method is always an uppercased string.
*
* @return string The request method
*
* @api
*
* @see getRealMethod()
*/
public function getMethod()
{
if (null === $this->method) {
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' === $this->method) {
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
}
}
}
return $this->method;
}
The previous constant value should be true
but shomehow, when I run the test its value is false
.
I found a solution but I don't think this is the right place to write it.
I added a simple line of code on the Connector\Laravel5
class.
public function __construct($module)
{
$this->module = $module;
$this->initialize();
$components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
$host = isset($components['host']) ? $components['host'] : 'localhost';
parent::__construct($this->app, ['HTTP_HOST' => $host]);
// Parent constructor defaults to not following redirects
$this->followRedirects(true);
// Added to solve the problem of overriding the request method
Request::enableHttpMethodParameterOverride();
}
This solves my problem.
这篇关于Laravel和Codeception - 测试在PUT表单上失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!