この記事では、PHPUnitでデータプロバイダを使う方法を解説します。
データプロバイダを効果的に使うことで、同じ処理を何度も書く必要がなくなり、テストコードをDRY(Don’t Repeat Yourself:同じことを繰り返すな)に保つことができます。
書き方自体は難しくないので、ぜひ参考にしてみて下さい。
PHP:7.3.23
Laravel:8.0
PHPUnitのデータプロバイダはどのような場面で有効か?
最初に、どのような場面でデータプロバイダが有効なのかを解説します。
PHPUnitでデータプロバイダが有効なのは、例えば以下のようなコードです。
<?php namespace App\Services; class ExampleService { public function calculate(int $a, int $b) { return $a + $b * 2; } }
<?php namespace Tests\Services; use App\Services\ExampleService; use Tests\TestCase; class ExampleServiceTest extends TestCase { /** @test */ public function 引数に1と1が渡った場合は3が返る() { $this->assertEquals(3, (new ExampleService)->calculate(1, 1)); } /** @test */ public function 引数に0と1が渡った場合は2が返る() { $this->assertEquals(2, (new ExampleService)->calculate(0, 1)); } /** @test */ public function 引数に1と0が渡った場合は1が返る() { $this->assertEquals(1, (new ExampleService)->calculate(1, 0)); } /** @test */ public function 引数に0と0が渡った場合は0が返る() { $this->assertEquals(0, (new ExampleService)->calculate(0, 0)); } }
テストコードに同じような処理が並んでいます。
使っているアサーション(assertEquals)は同じですし、メソッドを呼び出す処理も全て同じです。
違っているのは、テスト名と引数の値くらいです。
このような場面では、データプロバイダを活用することで、同じ処理を何度も書くことなくテストファイルをシンプルに保つことができます。
また、その他にもデータプロバイダには以下のようなメリットがあります。
- setUp/tearDownが毎回実行される
- どのテストが落ちたのかが分かりやすい
詳しく知りたい方は以下の記事を参考にしてみて下さい。
PHPUnitでデータプロバイダを使う方法
データプロバイダの使い所が分かったところで、先ほどのテスト(以下に再掲)をデータプロバイダを使って書き直してみます。
<?php namespace Tests\Services; use App\Services\ExampleService; use Tests\TestCase; class ExampleServiceTest extends TestCase { /** @test */ public function 引数に1と1が渡った場合は3が返る() { $this->assertEquals(3, (new ExampleService)->calculate(1, 1)); } /** @test */ public function 引数に0と1が渡った場合は2が返る() { $this->assertEquals(2, (new ExampleService)->calculate(0, 1)); } /** @test */ public function 引数に1と0が渡った場合は1が返る() { $this->assertEquals(1, (new ExampleService)->calculate(1, 0)); } /** @test */ public function 引数に0と0が渡った場合は0が返る() { $this->assertEquals(0, (new ExampleService)->calculate(0, 0)); } }
上記のコードは、データプロバイダを使うと以下のように書き直せます。
<?php namespace Tests\Services; use App\Services\ExampleService; use Tests\TestCase; class ExampleServiceTest extends TestCase { /** * @dataProvider calculationDataProvider * @test */ public function 計算のテスト($a, $b, $expected_result) { $this->assertEquals($expected_result, (new ExampleService)->calculate($a, $b)); } // [$a, $b, $expected_result] public function calculationDataProvider() { return [ '引数に1と1が渡った場合は3が返る' => [1, 1, 3], '引数に0と1が渡った場合は2が返る' => [0, 1, 2], '引数に1と0が渡った場合は0が返る' => [1, 0, 1], '数に0と0が渡った場合は0が返る' => [0, 0, 0] ]; } }
ポイントは以下の3点です。
- データプロバイダメソッド内の連想配列で、テストメソッドの引数に渡す値を指定できる
- データプロバイダメソッドはpublicである必要がある
- テストメソッドに@dataProviderアノテーションと対応するデータプロバイダ名を指定することで、テストメソッドの引数にデータプロバイダで登録した値を渡せる
それでは実際にテストを実行してみましょう。
まずは全てのテストが通るパターンです。
データプロバイダに登録したそれぞれの配列が一つのテストとして認識されていることが分かると思います。
次に、一つのテストが失敗するパターンです。
データプロバイダの連想配列のキーで指定したテスト名が表示されています。
このように、データプロバイダを使うことで、テストとしての従来の機能は保ちつつ、コードをシンプルに実装することができます。
PHPUnitでデータプロバイダを使う方法まとめ
今回はPHPUnitでデータプロバイダを使う方法を解説しました。
データプロバイダはコードをDRYに保つ上で非常に便利な機構です。
もちろん、全ての場面で有効なわけではありませんが、同じテストを何度も書いている場合はデータプロバイダが使えないかを考えてみるようにしましょう。