How to mock an annotated AWS method in PHPUnit?
Asked Answered
B

1

6

I am writing a unit test and I want to check whether the method publish() was called one or more times. This is a snippet from my whole test class:

<?php

namespace App\Tests\Unit;

use Aws\Sns\SnsClient;
use Exception;
use PHPUnit\Framework\TestCase;

class MyClassTest extends TestCase
{
    /** @var SnsClient */
    private $snsClient;

    public function setUp(): void
    {
        $this->snsClient = $this->getMockBuilder(SnsClient::class)->disableOriginalConstructor()->getMock();
    }

    /**
     * @throws Exception
     */
    public function testNoCaseIdentifierSns()
    {
        $this->snsClient->expects($this->once())->method('publish')->with([
            [
                'doc_id' => 1,
                'bucket' => 'some_bucket',
                'key'    => 'test.tiff/0.png'
            ],
            'topic_arn'
        ]);
    }
}

But when I run the code above I got the following error:

Trying to configure method "publish" which cannot be configured because it does not exist, has not been specified, is final, or is static

I guess the problem here is the method in AWS is defined as @method (see here):

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

It is possible to mock that method? What I am missing here?

UPDATE

After following comments suggestions I transformed my code into the following:

$this->snsClient->expects($this->once())->method('__call')->with([
    'Message'  => json_encode([
        'doc_id' => 1,
        'bucket' => 'some_bucket',
        'key'    => 'test.tiff/0.png'
    ]),
    'TopicArn' => 'topic-arn'
]);

But now I am getting this other error:

Expectation failed for method name is equal to '__call' when invoked 1 time(s) Parameter 0 for invocation Aws\AwsClient::__call('publish', Array (...)) does not match expected value. 'publish' does not match expected type "array".

Why? publish() method signature is an array of args

Blowbyblow answered 18/7, 2019 at 19:5 Comment(5)
The method does not actually exist. All listed methods are implemented through the magic method __call. You need to mock the magic method.Sldney
@CharlotteDunois can you provide me with an example? I am new to PHPUnit :|Blowbyblow
It's the same as any other method, except that the function signature of __call is string $name, array $args, so you only need to adjust your code to reflect that you're invoking a magic method.Sldney
@CharlotteDunois your suggestion kind of worked but now I am getting a different error and I am not sure what else I am missingBlowbyblow
You forgot the name of the method (publish) and don't forget that __call receives an array of arguments and not the plain argument. Since the sole argument is an array, the second argument to with should be an array of arrays (an array wrapping the sole argument).Sldney
S
7

From the thrown exception, we see that the __call function is called with the name of the target function (i.e. 'publish') and an array containing all arguments. As a result, here is how the mock setup can be updated:

$event = [
    'Message'  => json_encode([
        'doc_id' => 1,
        'bucket' => 'some_bucket',
        'key'    => 'test.tiff/0.png'
    ]),
    'TopicArn' => 'topic-arn'
];
$this->snsClient
    ->expects($this->once())
    ->method('__call')
    ->with('publish', [$event]);

Siphonophore answered 27/3, 2020 at 12:57 Comment(1)
Note the wrapping array of [$event] Must not be ['Message' => 'foo', 'TopicArn' => 'bar'] Must be [['Message' => 'foo', 'TopicArn' => 'bar']]Geraud

© 2022 - 2024 — McMap. All rights reserved.