Api 平台:如何使用 ApiTestCase 测试文件上传

Api Platform: how to test file upload with ApiTestCase

我有一个允许文件上传的端点,一切正常。 接下来是用适当的功能测试覆盖端点。 这就是问题所在 - 我无法将 file 传递给发出请求的客户端。

我的测试 class 扩展 \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 testsApiTestCase 来测试文件上传端点?

下面是一些代码,可以帮助您直观地了解问题:

Api实体中的资源定义:

/**
 * @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"
 *                                     }
 *                                 }
 *                             }
 *                         }
 *                     }
 *                 }
 *             }
 *         },
 *     },
 * )
 */

测试class(不要介意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.

上传文件

自从当前最新版本 api-platform/core (2.5.8) 以来,我们可以通过 extra 键将更多参数传递给 kernelBrowser->request。这现在也包括文件!

下面是一个非常基本的图片上传测试示例(基于official API Platform documentation实现):


$file = new UploadedFile(
    'path/to/images/my_image.png',
    'my_image.png',
    'image/png',
);

$response = static::createClient()->request('POST', '/upload_image',
    [
        'headers' => ['Content-Type' => 'multipart/form-data'],
        'extra' => [
            'files' => [
                'file' => $file,
            ],
        ],
    ],
);