如何使用Symfony测试客户端检索流响应(例如下载文件)

18

我正在使用Symfony2编写功能测试。

我有一个控制器调用了一个getImage()函数,该函数将图像文件流式传输,如下所示:

public function getImage($filePath)
    $response = new StreamedResponse();
    $response->headers->set('Content-Type', 'image/png');

    $response->setCallback(function () use ($filePath) {
        $bytes = @readfile(filePath);
        if ($bytes === false || $bytes <= 0)
            throw new NotFoundHttpException();
    });

    return $response;
}

在功能测试中,我尝试使用Symfony测试客户端请求内容,如下所示:

$client = static::createClient();
$client->request('GET', $url);
$content = $client->getResponse()->getContent();

问题在于$content为空,我猜测这是因为响应是在客户端接收到HTTP头之后立即生成的,而不等待数据流传递。

是否有一种方法可以在仍然使用$client->request()(或甚至其他一些函数)向服务器发送请求的情况下捕获流式响应的内容?

3个回答

23
sendContent方法的返回值是您设置的回调函数,而不是getContent方法。在Symfony2中,getContent实际上只返回false
使用sendContent方法,您可以启用输出缓冲并将内容分配给它以供测试,如下所示:
$client = static::createClient();
$client->request('GET', $url);

// Enable the output buffer
ob_start();
// Send the response to the output buffer
$client->getResponse()->sendContent();
// Get the contents of the output buffer
$content = ob_get_contents();
// Clean the output buffer and end it
ob_end_clean();

您可以在这里了解有关输出缓冲的更多信息:这里

StreamResponse的API在这里:这里


3
为了让这个工作起来,我必须在发出请求之前先调用ob_start()。 - Marcel Pfeiffer

10

对我来说不起作用。相反,我在发出请求之前使用了ob_start(),在请求完成后使用了$ content = ob_get_clean()并对该内容进行了断言。

测试中:

    // Enable the output buffer
    ob_start();
    $this->client->request(
        'GET',
        '$url',
        array(),
        array(),
        array('CONTENT_TYPE' => 'application/json')
    );
    // Get the output buffer and clean it
    $content = ob_get_clean();
    $this->assertEquals('my response content', $content);

也许这是因为我的响应是一个CSV文件。

在控制器中:

    $response->headers->set('Content-Type', 'text/csv; charset=utf-8');

1
谢谢,对我也起作用了,同时使用 Symfony\Component\HttpFoundation\Response 对象。 - Julien Fastré

9

这个最佳答案曾经很适合我使用,但出于某些原因现在不再有效了。响应被解析成DOM爬虫,并且二进制数据丢失了。

我可以通过使用内部响应来修复这个问题。这是我的更改的git补丁[1]:

-        ob_start();
         $this->request('GET', $uri);
-        $responseData = ob_get_clean();
+        $responseData = self::$client->getInternalResponse()->getContent();

希望这能对某些人有所帮助。

[1]: 您只需要访问客户端,该客户端是一个Symfony\Bundle\FrameworkBundle\KernelBrowser对象。


太棒了,伙计!你刚刚帮我解决了一个大问题。 - Borza Adrian
1
在Symfony 6中,$client->getInternalResponse()->getContent()完成了这项工作。谢谢。 - Pedro Casado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接