测试流式响应

时间:2018-08-15 10:51:04

标签: php laravel phpunit

我有以下路线:

Route::get('echo',function (Request $req) {
    return response()->stream(function () use ($req) {
        echo json_encode($req->all());
    }, 200, [
        'Content-Type' => 'application/json'
    ]);
})->name('echo');

为简单起见,让我们假设它是一个简单的回声响应。实际上,这是一个非常大的文件。两种情况下的结果都是相同的。

现在我要测试此路由,以查看是否确实可以看到json内容,所以我尝试了以下方法:

public function testBasicTest()
{

    $response = $this->get(route('echo', [
        "content"=>"some content"
    ]));
    $response->assertSeeText("some content"); //Doesn't work
    $response->assertJson( [
        "content"=>"some content"
    ]); //Neither does this
}

我已经对其进行了进一步检查,这似乎是因为(a)响应被包裹在TestResponse周围(b)响应内容从未流过,并且(c)即使响应内容是要通过$response->baseResponse->sendContent()强制流式传输,则实际返回的内容实际上并未被TestResponse

捕获

另外,调用$response->getContent()不起作用,因为它似乎直接调用了StreamedResponse::getContent(),后者被硬编码为返回false

使用以下方法,我取得了一些有限的成功:

ob_start();
$response->sendContent();
$result = ob_get_clean();

但是,在单元测试中,这看起来很草率。

之前有人遇到过吗?是否可以测试流式响应的内容?

2 个答案:

答案 0 :(得分:2)

这不是一个好的解决方案,更像是一个hack,但是如果其他任何人遇到此问题,您可以执行以下操作:

public function testBasicTest()
{

    $response = $this->get(route('echo', [
        "content"=>"some content"
    ]));
    if ($response->baseResponse instanceof StreamedResponse) {
            ob_start();
            $response->sendContent();
            $content = ob_get_clean();
            $response = new TestResponse(
                new Response($content, 
                             $response->baseResponse->getStatusCode(), 
                             $response->baseResponse->headers->all()
                )
            );
    }
    $response->assertSee("some content"); //Works
}

答案 1 :(得分:2)

聚会有点晚,但可能会帮助其他人。

在 Laravel 中,您可以在处理 $response->streamedContent() 时执行 StreamedResponse(我相信从 5.8 开始)。

即使我的调试器告诉我响应的流式内容是 null,我仍然从中获取数据。

就我而言,它是 CSV,所以在我完成的功能测试中:

$res = $this->post('api/v1/entity/export', $payload, $header);
$res->assertStatus(200);
$res->assertHeader('Content-Disposition', 'attachment; filename=entity.csv');

$reader = Reader::createFromString($res->streamedContent());
// tests...

我使用了 LeagueCSV(显然它是 CSV),但我相信你可以用 Json 或其他方式做同样的事情。

Laravel doc for TestResponse