【发布时间】:2020-11-15 04:26:51
【问题描述】:
我有一个端点,允许文件上传,一切正常。
接下来是用适当的功能测试覆盖端点。
这就是问题所在 - 我无法将 file 传递给发出请求的客户端。
我的测试类扩展了\ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase。
static::createClient() 方法创建了一个ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client 的实例,而这些Client 不支持文件上传。
因为实现了定义public function request(string $method, string $url, array $options = []): ResponseInterface; 的Symfony\Contracts\HttpClient\HttpClientInterface,所以没有地方传递files 参数。
Client 中允许的options 不支持files 数组。
内部是这样的:
ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client::request 传递给内部kernelBrowser 一个空数组代替files 参数(第二个数组):$this->kernelBrowser->request($method, $resolvedUrl, [], [], $server, $options['body'] ?? null)
如何通过扩展Base class for functional API tests(即ApiTestCase)来测试带有文件上传的端点?
这里有一些代码,可以帮助您将问题可视化:
实体中的ApiResource定义:
/**
* @ApiResource(
* collectionOperations={
* "file_upload"={
* "method"="post",
* "controller"=FileUpload::class,
* "path"="/api/file-upload-endpoint",
* "deserialize"=false,
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* },
* },
* )
*/
测试类(不要介意UploadedFile的实例,它就在那里,向你展示它不能在任何地方传递):
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
这就是我要找的东西:
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
[
'file'=>$file
]
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
当修改vendor 本身并将files 传递给Client::request 然后传递给kernelBrowser 代替第二个空数组时,一切正常(我知道违反合同,那不是这里的问题;))。
我在想ApiTestCase中是否缺少上传文件的功能,或者我找不到解决方案。
请停下!
Api 平台版本:2.5.6
PS:我知道我可以使用不同的客户端 - test.client
$client = static::$kernel->getContainer()->get('test.client');
这是Symfony\Bundle\FrameworkBundle\KernelBrowser 的一个实例,与Api 平台的Client 内部使用的相同,并且支持 files 数组,但这不是我的问题的重点。我想知道如何使用ApiTestCase进行文件上传。
【问题讨论】:
-
this 有用吗? ctrl + f 提交带有文件上传的表单_.
-
很遗憾没有。
Client::request使用的kernelBrowser->request扩展Symfony\Component\BrowserKit\AbstractBrowser和body参数必须是string或null。它不接受object、resource和其他在HttpClient中允许的内容。 -
content参数,具体来说。来自Client::request的body参数在内部传递给KernelBrowser作为content参数。 -
@MarekSkopowski 你有没有设法做到这一点?
-
@AnonymousAngelo 信不信由你,但昨天我为关闭这个问题而奋斗;)
标签: php symfony upload functional-testing api-platform.com