【问题标题】:Laravel and Codeception - test fails on PUT formsLaravel 和 Codeception - PUT 表单上的测试失败
【发布时间】:2016-01-21 11:28:29
【问题描述】:

我在 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 运行测试并提交表单时,我得到一个方法不允许的异常并且测试失败。

我试图了解为什么会发生这种情况,这似乎是 codeception 发出的请求。该请求是使用 POST 而不是 PUT 方法发出的,这会阻止 Laravel 匹配路由。

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

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

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

我该如何解决这个问题?

编辑:深入研究代码,我发现测试不会覆盖请求方法,因为Request 类中的一个常量称为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

【问题讨论】:

  • 使用 -vv 标志运行测试以查看实际发送的参数。
  • 完成。输出显示 Codeception 如何按预期执行带有 _method = PUT 属性的 POST 请求。但不知何故,这与我定义的 PUT 路由不匹配。但是,在 Web 浏览器中执行此操作匹配正确。
  • 我在更新处理上有同样的问题。我系统地有一个 404 错误。事实上,更新方法并没有在我的控制器中执行,这导致更新 url 上的代码接收没有在更新方法中处理后应该发生的重定向。自从两周以来我一直在阻止这个问题,但没有找到任何解决方案或找到解决方案的线索。
  • 请停止写 Codeception 没有读取 _method 值,您已经确认 _method 在请求中传递。
  • 由 Laravel 来解释参数并调用正确的方法。 Codeception 测试套件包括 Laravel5 站点,该站点的测试形式与您的相似,方法设置为 PATCH 并通过:github.com/janhenkgerritsen/codeception-laravel5-sample/blob/…

标签: php forms laravel laravel-5 codeception


【解决方案1】:

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

    // Parent constructor defaults to not following redirects
    $this->followRedirects(true);

    // Added to solve the problem of overriding the request method
    Request::enableHttpMethodParameterOverride();
}

这解决了我的问题。

【讨论】:

  • 下次您执行composer update 时,这些更改将丢失。
  • 对。我应该把这段代码放在哪里?测试/接受/_bootstrap.php 也许?
  • 我终于通过在tests/_bootstrap.php 文件中编写下一行代码来解决它。 \Symfony\Component\HttpFoundation\Request::enableHttpMethodParameterOverride();
【解决方案2】:

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

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

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

【讨论】:

  • 我已经这样做了。 Laravel Form 助手类将该代码转换为上面的 HTML 代码。问题是 Codeception 没有读取 _method 值。
猜你喜欢
  • 2015-12-29
  • 2016-05-01
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 2018-01-04
  • 2016-06-28
相关资源
最近更新 更多