AWS SDK for PHPのクラスをPHPUnitでモックしようとした所次のようなエラーが発生しました。
public function testExample()
{
$s3Client = $this->createMock(S3Client::class);
$s3Client->method('GetObject');
}
エラー内容
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.
Trying to configure method "GetObject" which cannot be configured because it does not exist, has not been specified, is final, or is static
/path/to/test/ExampleTest.php:18
Time: 00:00.017, Memory: 14.00 MB
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
実装を見るとわかるのですが、GetObject()
はAws\S3\S3Client
クラスのdocコメントに書いてあるだけで実際には存在しません。内部の処理がどうなっているのかはわかりませんが、どうやら実行時によしなに解決されているようです。
しかし、メソッドがクラスに存在しないということは、PHPUnitのcreateMock()
でモックすることができません。困った。
どうする
createMock()
ではなくcreatePartialMock()
メソッドを使います。このメソッドは第二引数にメソッド名の配列を受け取り、モックオブジェクトを作る時にこれらのメソッドをモック対象として追加してくれます。
public function testExample()
{
$s3Client = $this->createPartialMock(S3Client::class, ['GetObject']);
$s3Client->method('GetObject');
}
エラーが消えた!しかし、警告が出ています。存在しないメソッドのモックは良くないらしく、将来的にはサポートされなくなるそうです。ぐぬぬ。
createPartialMock() called with method(s) GetObject that do not exist in Aws\S3\S3Client. This will not be allowed in future versions of PHPUnit.
Time: 00:00.017, Memory: 12.00 MB
WARNINGS!
Tests: 1, Assertions: 0, Warnings: 1.
その他の方法
AWS SDK for PHPには各サービスをモックする方法が提供されています。PHPUnitのモックを使うよりも冗長になりますが、基本はこちらを使うのが今のところベストかと思います。
しかし、こちらの方法では「どのメソッドが」「どの引数で」「何回呼び出された」というようなことは確かめられないので、それらをテストする必要がある場合は非推奨ですが、PHPUnitでのモックをすることになると思います。