AWS SDK for PHP を Mock する #php

AWS SDK を使って Amazon SNS 使用箇所のテストを書こうとしていたところ、 PHPUnit の Mock を無邪気に使ったら怒られてしまった。

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

どうやら PHPUnit で簡単には Mock できない構造のようだが、調べてみると MockHandler を使えば良さそうだ。

Handlers and Middleware in the AWS SDK for PHP Version 3 - AWS SDK for PHP

<?php
// handler を作成
$mock = new MockHandler();

// mock の中身を定義
$mock->append(new Result(['foo' => 'bar']));

// 例外も返せる
$mock->appendException(
    new SnsException('Mock exception', $this->createStub(Command::class))
);

// client を生成
$client = new SnsClient(
    [
        'version' => cr('ExServices.Sns.version'),
        'region' => cr('ExServices.Sns.region'),
        // handler を渡してあげる
        'handler' => $mock,
    ]
);

// mock した結果は queue 方式で実行される
$client->publish(['Message' => 'dummy']);

// queue 方式なので、2回目は例外が発生する
$client->publish(['Message' => 'dummy']);

ここまではドキュメントの通りなのだが、認証情報が未設定だと CredentialsException が発生してしまう。

Aws\Exception\CredentialsException : Error retrieving credentials from the instance profile metadata service. (cURL error 7: Failed to connect to 169.254.169.254 port 80 after 0 ms: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html))

どこまで何をテストしたいかによるが、手軽に SnsClient を Mock したいだけなら匿名クライアントにすれば回避できる。

Creating Anonymous Clients - AWS SDK for PHP

<?php
// client を生成
$client = new SnsClient(
    [
        'version' => cr('ExServices.Sns.version'),
        'region' => cr('ExServices.Sns.region'),
        'handler' => $mock,
        // credentials を false にすれば匿名クライアントになる
        'credentials' => false,
    ]
);