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

Cal*_*ane 2 php phpunit amazon-s3

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

\n

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

\n

我现在所做的:

\n

在我的服务中:

\n
class AwsS3Service implements AwsS3ServiceInterface\n{\n    private S3Client $s3Client;\n    ....\n\n    public function __construct(ParameterBagInterface $params)\n    {\n        [ ... ]\n\n        $this->s3Client = $this->getS3client();\n    }\n\n    public function getS3client(): S3Client\n    {\n        return (new Sdk($this->config))->createS3();\n    }\n\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n
        $this->awsS3Service = $this->createMock(AwsS3ServiceInterface::class);\n\n        $command = $this->createMock(Command::class);\n        /** @var S3Client $s3Client */\n        $s3Client = $this->createMock(S3Client::class);\n\n        $s3Client->method(\'listObjectsV2\')\n                 ->willThrowException(new S3Exception(\'VALIDATION ERROR\', $command));\n        $s3Client->method(\'putObject\')\n                 ->willThrowException(new S3Exception(\'VALIDATION ERROR\', $command));\n        $s3Client->method(\'getObject\')\n                 ->willThrowException(new S3Exception(\'VALIDATION ERROR\', $command));\n        $s3Client->method(\'deleteObject\')\n                 ->willThrowException(new S3Exception(\'VALIDATION ERROR\', $command));\n\n        $this->awsS3Service\n            ->method(\'getS3client\')\n            ->willReturn($s3Client);\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
Aws S3Service (App\\Tests\\Unit\\Domain\\AwsS3\\AwsS3Service)\n \xe2\x9c\x98 Aws upload file s 3 exception\n   \xe2\x94\x90\n   \xe2\x94\x9c 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\n   \xe2\x94\x82\n   \xe2\x95\xb5 /var/www/tests/Helper/AwsMockHelper.php:34\n   \xe2\x95\xb5 /var/www/tests/Unit/Domain/AwsS3/AwsS3ServiceTest.php:35\n   \xe2\x94\xb4\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
 * @method \\Aws\\Result listObjectsV2(array $args = [])\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

Cal*_*ane 5

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

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

此链接下的评论让我走上了正轨: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));
Run Code Online (Sandbox Code Playgroud)