はじめに
PHPのGuzzleHttp *1 を利用し、以下のようなコードを書いた。
<?php try { // $this->guzzleClient は コンストラクタDIなどを利用して // $this->guzzleClinet = new \GuzzleHttp\Client(); を差し込むようにする $response = $this->guzzleClient->post($url); } catch (\GuzzleHttp\Exception\GuzzleException $e) { // GuzzleExceptionを独自定義の例外に置き換えて投げる throw new MyInternalErrorException(); }
ここで、 GuzzleException
をキャッチしたあとの処理が正しく行われているかをテストしたい。
環境
問題点
通常であれば以下のようにテストをしたい
<?php public function test() { $this->expectException(MyInternalErrorException::class); $this->guzzleClient->shouldReceive('post') ->andThrow(new \GuzzleHttp\Exception\GuzzleException()); // 実際にメソッドが呼んで例外が投げられるかを確認する }
しかしここで問題がある。 GuzzleException
は interface なので *2 new できないのだ。
<?php namespace GuzzleHttp\Exception; interface GuzzleException {}
次に以下を試す
<?php public function test() { $this->expectException(MyInternalErrorException::class); $this->guzzleClient->shouldReceive('post') ->andThrow(\Mockery::mock(\GuzzleHttp\Exception\GuzzleException::class)); // 実際にメソッドが呼んで例外が投げられるかを確認する }
これもまだ問題がある。GuzzleException
はただの interface であり、Throwable
を実装していないので、例外として投げることはできず Mockery でエラーとなる。
仕方ないので、実際に GuzzleException
を継承したクラスをThrowすることが考えられる。例えば、Guzzleには TransferException
というものがある。
<?php namespace GuzzleHttp\Exception; class TransferException extends \RuntimeException implements GuzzleException {}
しかしこれにもまだ問題がある。
TransferException
が万が一GuzzleException
でなくなったり、消えたりした場合にテストが落ちる。TransferException
以外の GuzzleException にも対応できているのかがわからない。
ではどうすればいいのか。
解決方法
実は Mockery::mock
にはクラスとインタフェースを両方とれたり、インタフェースを複数取れたりする機能があるのでそれを使う。
<?php public function test() { $exceptionMock = \Mockery::mock(\Exception::class, \GuzzleHttp\Exception\GuzzleException::class) $this->expectException(MyInternalErrorException::class); $this->guzzleClient->shouldReceive('post') ->andThrow($exceptionMock); // 実際にメソッドが呼んで例外が投げられるかを確認する }
こうすると、GuzzleException
を implements し Exception
を継承したクラスが出来上がる。以下のようなイメージだ。
<?php class MockeryMockException extends Exception implements GuzzleException
これで Exception
は thorwable なのでこれで問題は解決だ。( Exception
でなくても、 RuntimeException
くらいでもいいかもしれない)
まとめ
Mockeryのmockメソッドは複数引数を与えるとインタフェースを実装したクラスをモックしたり、複数のインタフェースを実装したクラスをモックできる!!!
参考
- 作者: 谷藤賢一,河原健人
- 出版社/メーカー: リックテレコム
- 発売日: 2011/12/09
- メディア: 大型本
- 購入: 10人 クリック: 129回
- この商品を含むブログ (7件) を見る
- 作者: 谷藤賢一,徳丸浩(協力)
- 出版社/メーカー: リックテレコム
- 発売日: 2017/02/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る