はじめに
LaravelでUnitテストを書いていて、AWS SDKに依存する部分のMockで死ぬほど詰まっていたところ先輩に教えてもらいました。AWS SDK for PHPの内部では、Client ClassのAnnotationにメソッド定義のみを行い、Annotationに定義された内容に適した実装を注入していくような形になっているので、Mockryで素直にMockする事ができませんでした。(気になる人はAWS SDK for PHPの実装をチェック)
Aws\MockHandlerを使う
AWS SDK for PHPバージョン 3 でのハンドラーとミドルウェア
上記のドキュメントのMock ハンドラーという小節にあるサンプルコードが非常に明快です。
use Aws\Result;
use Aws\MockHandler;
use Aws\DynamoDb\DynamoDbClient;
use Aws\CommandInterface;
use Psr\Http\Message\RequestInterface;
use Aws\Exception\AwsException;
$mock = new MockHandler();
// Return a mocked result
// AWS系のサービスから返って来て欲しい値をMockHandlerのキューにエンキュー
$mock->append(new Result(['foo' => 'bar']));
// You can provide a function to invoke; here we throw a mock exception
// こんな感じで例外もエンキューできる
$mock->append(function (CommandInterface $cmd, RequestInterface $req) {
return new AwsException('Mock exception', $cmd);
});
// Create a client with the mock handler
// クライアントをインスタンス化する際にhanlderにMockHandlerインスタンスを渡す
$client = new DynamoDbClient([
'region' => 'us-west-2',
'version' => 'latest',
'handler' => $mock
]);
// Result object response will contain ['foo' => 'bar']
// 何らかのAWS系サービスと通信を行うメソッドを実行するとMockHandlerに登録された内容がデキューされ返される
$result = $client->listTables();
// This will throw the exception that was enqueued
// キューなので2回目に叩くと登録した例外が返ってくる
$client->listTables();
公式のドキュメントではDynamoDbClient、ネットの記事ではS3Client、私の検証ではCognitoProviderClientでも同様の手順でMockする事ができました。
AWS SDK for PHPを使ったUnitテストでお困りの方はお試しあれ。