【问题标题】:Api Platform: how to test file upload with ApiTestCaseApi 平台:如何使用 ApiTestCase 测试文件上传
【发布时间】: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-&gt;request 扩展 Symfony\Component\BrowserKit\AbstractBrowserbody 参数必须是 stringnull。它不接受objectresource 和其他在HttpClient 中允许的内容。
  • content 参数,具体来说。来自Client::requestbody 参数在内部传递给KernelBrowser 作为content 参数。
  • @MarekSkopowski 你有没有设法做到这一点?
  • @AnonymousAngelo 信不信由你,但昨天我为关闭这个问题而奋斗;)

标签: php symfony upload functional-testing api-platform.com


【解决方案1】:

由于当前最新版本的api-platform/core (2.5.8) 我们能够通过extra 键将更多参数传递给kernelBrowser-&gt;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,
            ],
        ],
    ],
);

【讨论】:

  • 您好,感谢您的更新。我打算做一个 PR 来解决这个问题,但我注意到有人已经这样做了。
  • 别担心!如果您认为我的回答有帮助,您介意将其标记为已接受的答案吗? :)
  • 是的,您的答案正是人们想要的。不幸的是,我的声誉(目前为 11)不允许我公开投票 - “不要更改公开显示的帖子分数”¯_(ツ)_/¯
  • 啊我明白了 :) 所以你甚至不能点击绿色复选标记?
  • 哈哈,我一定是瞎了。接受的答案:+1
猜你喜欢
  • 2021-09-18
  • 1970-01-01
  • 2020-11-05
  • 2019-10-03
  • 2020-08-19
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
相关资源
最近更新 更多