带有 JSON 请求的 Laravel/phpunit 测试丢失了重要的请求细节

Posted

技术标签:

【中文标题】带有 JSON 请求的 Laravel/phpunit 测试丢失了重要的请求细节【英文标题】:Laravel/phpunit test with JSON request loses important request details 【发布时间】:2018-09-26 03:11:52 【问题描述】:

我有一个简单的测试,我想断言一个特定的 JSON 响应。测试(修剪)如下所示:

$response = $this->json('POST', '/api/auth/register', [
        'client_id' => $client->id,
        'client_secret' => $client->secret
    ]);

$response->assertStatus(422);

$response->assertJson([
        'error' => 'validation_error',
        'message' => 'There were validation errors with the form input.'
    ]);

相当基本的东西。出现问题的地方是,在我的应用程序中,我有一个开关,可以根据 URL 有条件地加载不同的异常处理程序。这看起来像这样:

if(request()->is('api/*')) 
    return new Optimus\Heimdal\ExceptionHandler($app);

如果我在 curl 或 postman 中运行请求,没问题。但是,在 php 单元中,它不会在路径上拾取,就好像路径没有被传递一样。为了解决这个问题,我用wantsJson() 的检查替换了这个路径检查,但这也不起作用。

这似乎与https://github.com/laravel/lumen-framework/issues/55 相关 - 不过我还没有得出解决方案!

我想至少更好地理解这一点。一个合适的解决方案是可取的,否则我会看到一个肮脏的黑客攻击,未来我可能会忘记!

任何帮助表示赞赏。

【问题讨论】:

【参考方案1】:

好吧,再深入一点,它似乎与这个https://laravel-news.com/request-object-changes-in-lumen-5-4有关

我将条件代码移出到各自路由文件中的两个单独的代码块中。这行得通,但在这里改变环境感觉很讨厌。我暂时选择的“hack”是添加一个检查:

$app->runningInConsole()

这修复了测试。感觉不太满意,但如果删除它,所有测试都会爆炸,我会抓住它,所以我猜它会这样做。

【讨论】:

【参考方案2】:

我不完全理解为什么此时请求不可用的原因,但是使用两个处理程序的更可靠的方法是将应用程序的异常处理程序绑定到 optimus,而不是在它们之间进行交换。

请求被传递到render 并且report 应该无论如何都应该报告所有内容。

我在使用$app->runningInConsole() 时遇到的问题是它会导致测试中对 Web 异常的不同处理——例如未经身份验证的异常通常被捕获以通过 web 而非 api 触发重定向。

/**
 * Create a new exception handler instance.
 *
 * @param  \Illuminate\Contracts\Container\Container  $container
 * @return void
 */
public function __construct(Container $container)

    parent::__construct($container);

    $this->heimdal = new \Optimus\Heimdal\ExceptionHandler($container);


/**
 * Report or log an exception.
 *
 * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
 *
 * @param  \Exception  $exception
 * @return void
 */
public function report(Exception $exception)

    $this->heimdal->report($exception);

    parent::report($exception);


/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)

    if ($request->is('api/*')) 
        return $this->heimdal->render($request, $exception);
    

    return parent::render($request, $exception);

【讨论】:

以上是关于带有 JSON 请求的 Laravel/phpunit 测试丢失了重要的请求细节的主要内容,如果未能解决你的问题,请参考以下文章

带有 JSON 正文的 POST 请求

带有 JSON 请求的 Laravel/phpunit 测试丢失了重要的请求细节

是否可以在 Axios 中发送带有 JSON 正文的 get 请求?

带有重音/拉丁字符的 JSON 请求

使用 Volley 发送带有 JSON 数据的 POST 请求

带有 json 数据的 axios 发布请求