5

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

ReynierPM
  • 17,594
  • 53
  • 193
  • 363
  • The method does not actually exist. All listed methods are implemented through the magic method `__call`. You need to mock the magic method. – Charlotte Dunois Jul 18 '19 at 19:10
  • @CharlotteDunois can you provide me with an example? I am new to PHPUnit :| – ReynierPM Jul 18 '19 at 19:11
  • 1
    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. – Charlotte Dunois Jul 18 '19 at 19:13
  • @CharlotteDunois your suggestion kind of worked but now I am getting a different error and I am not sure what else I am missing – ReynierPM Jul 18 '19 at 19:27
  • 1
    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). – Charlotte Dunois Jul 18 '19 at 19:29

1 Answers1

6

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]);

Anthony Garant
  • 614
  • 7
  • 13
  • Note the wrapping array of `[$event]` Must not be `['Message' => 'foo', 'TopicArn' => 'bar']` Must be `[['Message' => 'foo', 'TopicArn' => 'bar']]` – Dave Apr 10 '20 at 06:30