php - How to Mock Aws\S3\S3Client for phpunit//如何模拟魔术方法

标签 php amazon-s3 phpunit

我需要在我的 symfony5 项目中模拟 S3Client,以便能够引发异常并测试我的代码对这些异常的 react 。我们使用 aws/aws-sdk-php 版本 3.*

7年前有人遇到了同样的问题,我尝试遵循这个解决方案[ PHPUnit - Mock S3Client not working well ] 但我收到错误。

我现在在做什么:

在我的服务中:

class AwsS3Service implements AwsS3ServiceInterface
{
    private S3Client $s3Client;
    ....

    public function __construct(ParameterBagInterface $params)
    {
        [ ... ]

        $this->s3Client = $this->getS3client();
    }

    public function getS3client(): S3Client
    {
        return (new Sdk($this->config))->createS3();
    }

所以我有一个公共(public)方法,我可以模拟它并使其返回一个模拟的 S3Client。

在我的测试中,我执行以下操作:

        $this->awsS3Service = $this->createMock(AwsS3ServiceInterface::class);

        $command = $this->createMock(Command::class);
        /** @var S3Client $s3Client */
        $s3Client = $this->createMock(S3Client::class);

        $s3Client->method('listObjectsV2')
                 ->willThrowException(new S3Exception('VALIDATION ERROR', $command));
        $s3Client->method('putObject')
                 ->willThrowException(new S3Exception('VALIDATION ERROR', $command));
        $s3Client->method('getObject')
                 ->willThrowException(new S3Exception('VALIDATION ERROR', $command));
        $s3Client->method('deleteObject')
                 ->willThrowException(new S3Exception('VALIDATION ERROR', $command));

        $this->awsS3Service
            ->method('getS3client')
            ->willReturn($s3Client);

现在,当我运行测试时,我收到错误

Aws S3Service (App\Tests\Unit\Domain\AwsS3\AwsS3Service)
 ✘ Aws upload file s 3 exception
   ┐
   ├ PHPUnit\Framework\MockObject\MethodCannotBeConfiguredException: Trying to configure method "listObjectsV2" which cannot be configured because it does not exist, has not been specified, is final, or is static
   │
   ╵ /var/www/tests/Helper/AwsMockHelper.php:34
   ╵ /var/www/tests/Unit/Domain/AwsS3/AwsS3ServiceTest.php:35
   ┴

问题似乎是,这些方法实际上并不存在于 S3Client 类中,而只是在该类的 PhpDoc 中以某种方式定义:

 * @method \Aws\Result listObjectsV2(array $args = [])

我们在编写服务时遵循了此文档: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html

最佳答案

通常,当您知道问题的名称时,会更容易找到解决方案。我相应地调整了问题标题。

在类的 header 中定义的方法实际上并不存在,称为“魔术方法”,有了这些知识,我找到了问题的解决方案:

此链接下的评论让我走上了正轨:https://carstenwindler.de/php/mocking-magic-methods-with-phpunit/

在当前版本的 phpunit 9.5 中,您可以使用 addMethods 和此语法来模拟魔术方法:

        $command = $this->createMock(Command::class);
        $s3Client = $this->getMockBuilder(S3Client::class)
                         ->disableOriginalConstructor()
                         ->addMethods(['listObjectsV2', 'putObject', 'getObject', 'deleteObject'])
                         ->getMock();

        $s3Client->expects($this->once())
                 ->method('listObjectsV2')
                 ->willThrowException(new AwsException('VALIDATION ERROR', $command));
        $s3Client->expects($this->once())
                 ->method('putObject')
                 ->willThrowException(new AwsException('VALIDATION ERROR', $command));
        $s3Client->expects($this->once())
                 ->method('getObject')
                 ->willThrowException(new AwsException('VALIDATION ERROR', $command));
        $s3Client->expects($this->once())
                 ->method('deleteObject')
                 ->willThrowException(new AwsException('VALIDATION ERROR', $command));

关于php - How to Mock Aws\S3\S3Client for phpunit//如何模拟魔术方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71497106/

相关文章:

php - 在单元测试中模拟私钥/公钥?

php - 通过用户角色 PHP 登录后重定向

amazon-s3 - 将数百万个文件从 S3 复制到 GCS 的最佳方式?

python - 在 AWS Lambda 中使用来自 S3 触发器的事件数据

android - 从 kotlin 应用程序在 s3 上上传音频文件

php - 如何让 PHPUnit 在测试路径中排除 .svn 目录?

php - Eclipse PDT 和自定义 PHPDoc 注释

php - 使用php将多个动态数据输入到mysql

javascript - JS 编码 HTML 标签不起作用

php - MySQL 多表全文搜索