Laravel 和 Codeception - PUT 表单测试失败

Laravel and Codeception - test fails on PUT forms

我在 laravel 中有一个资源控制器来管理我的用户。这将创建一个更新用户信息的路由,该路由接受使用 HTTP PUT 方法的请求。

这显示 artisan route:list 命令输出:

+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
| Domain | Method                         | URI                                                       | Name                                 | Action                                                                         | Middleware |
+--------+--------------------------------+-----------------------------------------------------------+--------------------------------------+--------------------------------------------------------------------------------+------------+
...
|        | PUT                            | users/{users}                                             | users.update                         | App\Http\Controllers\Users\UsersController@update                              | auth       |

它在我的网络浏览器上工作正常,但是当我尝试 运行 一个带有代码接收的测试并提交表单时,我得到一个方法不允许的异常并且测试失败。

我试着看看为什么会这样,这似乎是 codeception 提出的要求。该请求是使用 POST 而不是 PUT 方法发出的,从而阻止 Laravel 匹配路由。

HTML 表单不支持 PUT 方法,因此 Laravel Form 助手 class 创建如下表单:

<form method="POST" action="https://myapp.dev/users/172" accept-charset="UTF-8">
    <input name="_method" value="PUT" type="hidden">
...

但是,codeception 似乎没有读取 _method 值。

我该如何解决这个问题?

编辑:深入查看代码,我发现测试不会覆盖请求方法,因为 Request class 中的常量称为 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;
}

之前的常量值应该是true但是不知怎么的,当我运行测试的时候它的值是false.

您不能在 HTML 表单标签中使用 PUT 方法。为此,您需要使用 laravel 的 blade 模板格式来定义表单标签。

例如 {!! Form::open(['url' => 'users/{users}','method' => 'put','id' => 'form' ]) !!}

您也可以使用 route 属性来定义路由而不是 url

我找到了一个解决方案,但我认为这不是写它的正确位置。 我在 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();
}

这解决了我的问题。