I need to mock the S3Client in my symfony5 project to be able to provoke exceptions and test the reaction of my code to those exceptions. We use aws/aws-sdk-php version 3.*
7 Years ago someone had the same problem and I tried to follow this solution [ PHPUnit - Mock S3Client not working well ] but I get errors.
What I do at the moment:
in my service:
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();
}
So I have a public method, which I can mock and make it to give me back a mocked S3Client.
in my tests I do the following:
$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);
Now when I run the test I get the Error
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
┴
The problem seems to be, that the methods don't really exist in the S3Client class and are only somehow defined in the PhpDoc of the class:
* @method \Aws\Result listObjectsV2(array $args = [])
We followed this documentation, when writing the service: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html
CodePudding user response:
As often it is easier to find a solution, when you know the name of your problem. I adapted the question title accordingly.
Methods defined in the header of a class, which don't really exist are called "magic methods" and with that knowledge I found a solution to my problem:
A comment under this link set me on the right track: https://carstenwindler.de/php/mocking-magic-methods-with-phpunit/
In the current version of phpunit, which is 9.5, you can use addMethods and this syntax to mock magic methods:
$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));