How to Mock Aws\S3\S3Client for phpunit // 如何模拟魔术方法
How to Mock Aws\S3\S3Client for phpunit // how to mock magic methods
我需要在我的 symfony5 项目中模拟 S3Client,以便能够引发异常并测试我的代码对这些异常的反应。我们使用 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 class 中并不真正存在,只是在 class:
的 PhpDoc 中以某种方式定义
* @method \Aws\Result listObjectsV2(array $args = [])
我们在编写服务时遵循了这个文档:
https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html
当您知道问题的名称时,通常更容易找到解决方案。我相应地调整了问题标题。
在 class 的 header 中定义的方法实际上并不存在,被称为“魔术方法”,据此我找到了解决问题的方法:
这条 link 下的评论让我走上正轨: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));
我需要在我的 symfony5 项目中模拟 S3Client,以便能够引发异常并测试我的代码对这些异常的反应。我们使用 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 class 中并不真正存在,只是在 class:
的 PhpDoc 中以某种方式定义 * @method \Aws\Result listObjectsV2(array $args = [])
我们在编写服务时遵循了这个文档: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html
当您知道问题的名称时,通常更容易找到解决方案。我相应地调整了问题标题。
在 class 的 header 中定义的方法实际上并不存在,被称为“魔术方法”,据此我找到了解决问题的方法:
这条 link 下的评论让我走上正轨: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));