У меня следующий маршрут:
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
}
Я проверил его немного дальше, и, похоже, это связано с тем, что (а) ответ обернут вокруг TestResponse (б) содержимое ответа никогда не передается в потоковом режиме и (в) даже если содержимое ответа должно было быть принудительно передано в потоковом режиме через $response->baseResponse->sendContent(), фактическое содержимое отображается эхом, а не захватывается TestResponse
Вдобавок вызов $response->getContent() не работает, потому что кажется, что он напрямую вызывает StreamedResponse::getContent(), который жестко запрограммирован для возврата false.
Мне удалось добиться некоторого ограниченного успеха, используя:
ob_start();
$response->sendContent();
$result = ob_get_clean();
однако это выглядит как очень небрежная вещь в модульном тесте.
Кто-нибудь еще сталкивался с этим раньше? Можно ли проверить содержимое потокового ответа?






Это не лучшее решение, это скорее взлом, но если кто-то еще столкнется с этой проблемой, вот что вы можете сделать:
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
}
@TobiasK Я не знал об этом. Мне, наверное, следовало расширить свой поиск до Symfony, а не только до Laravel.
Никакой критики на ваш ответ. Я думаю, что вопрос в порядке, поскольку он относится к Laravel, в отличие от другого вопроса. Возможно, не всем понятно, что StreamedResponse является частью Symfony. Просто хотел представить то, что я нашел, в качестве контекста.
@TobiasK Я просто отмечаю, что больше самооценки, ваш комментарий был на самом деле очень полезным.
Немного поздно на вечеринку, но это может помочь кому-то другому.
В 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 для TestResponse
Некоторое время назад возник вопрос: stackoverflow.com/q/15734677/7362396 - и более "чистого" решения тоже не найдено :-(