
こんにちは、原田です。
前回、LaravelでService層とRepository層を取り入れる手順を紹介しました。
今回は各クラスで依存しているクラスをモックに差し替えて単体テストを書く方法を紹介します。
使用するMockeryのリファレンスはこちら。
テスト対象
テスト対象は前回の記事で作成したものとします。
こちら↓のSearviceクラスのgetSample()のテストを書いていきたいと思います。
class SampleService implements SampleServiceInterface
{
private $sample_repository;
public function __construct(
SampleRepositoryInterface $sample_repository
) {
$this->sample_repository = $sample_repository;
}
public function getSample($id);
{
return $this->sample_repository->getSampleById($id);
}
}
テストコード
テストコードがこちらになります。
ちなみにテストクラスはLaravelだとtests/Unitに配置するかと思いますが、その下にControllers、Servicesなどのフォルダを作成してからテスト対象に合わせて配置するのがおすすめです。
class SampleServiceTest extends TestCase
{
private $sample_repository_mock;
private $sample_id = 111;
public function setUp(): void
{
parent::setUp();
$this->sample_repository_mock = Mockery::mock(SampleRepository::class);
$this->instance(SampleRepositoryInterface::class, $this->sample_repository_mock);
}
public function testGetSample()
{
$this->sample_repository_mock
->shouldReceive('getSampleById')
->once()
->with($this->sample_id)
->andReturn(new Sample());
$service = new SampleService($this->sample_repository_mock);
$service->getSample($this->sample_id);
}
}
Mockeryの使い方
上のテストコード で何をやっているのか詳しく説明していきたいと思います。
まずsetUp()でモックを作成しています。
今回のテスト対象であるSampleServiceが依存しているSampleRepositoryをモック化します。
$this->sample_repository_mock = Mockery::mock(SampleRepository::class);
そして↓こちらでSampleRepositoryInterfaceの実装クラスををモックに差し替えています。
$this->instance(SampleRepositoryInterface::class, $this->sample_repository_mock);
次にtestGetSample()にて、モックに期待する結果を定義しています。
今回のテスト対象のメソッド内でSampleRepositoryのgetSampleByIdを呼び出します。
$this->sample_repository_mock
->shouldReceive('getSampleById')
->once()
->with($this->sample_id)
->andReturn(new Sample());
once()は呼び出される回数を定義します。
今回はgetSampleById()が一度だけ呼ばれるのでonce()を使っていますが、複数回呼ばれることが期待される場合はtimes($n)で指定できます。
次にwith()で期待される引数を定義します。
ここで指定したものと、実際のテストで渡されるものが異なっていた場合はテストが失敗するようになります。
最後にandReturnで、getSampleById()が呼び出された際の戻り値を指定できます。
そしてテストを行う際に作成したモックを渡してあげて、テスト対象のメソッドを呼び出せばOKです。
$service = new SampleService($this->sample_repository_mock);
$service->getSample($this->sample_id);
モックを使ったテストを調べているとonce()やwith()を指定しない書き方をしている方もいました。
それでもテスト自体はできるのですが、そのメソッドが呼び出されない、または期待される引数を渡せていなくてもテストが成功してしまうことがあります。
なので最低限once(),with()は指定することをお勧めします。
おわりに
今回は必要最低限のテストを書きましたが、例外を返す場合や、ファサードでモック化することもできたので機会があれば紹介したいと思います。