【PHPUnit】DataProvider を使ってみた!

こんにちは!
システム開発部の福井です!

今回は、PHPUnit で使用できる DataProvider というアノテーション(便利な仕組み)を使ってみたので、使用するに至った経緯・背景とともに使い方をご紹介させていただきます!
※本記事では「アノテーション自体の解説(アノテーションとは何か)」については割愛させていただきます。

DataProvider ってなに?

概要

簡単にいうと「PHPUnit のテストメソッドで任意の引数を複数使用できる便利な仕組み」です。
※ より詳細な解説やアノテーションについての解説を知りたいという方は、PHPUnit の公式ドキュメントを参照してください。

■ PHPUnit 公式ドキュメント
https://phpunit.de/documentation.html

■ DataProvider (アノテーション)について
https://docs.phpunit.de/en/11.0/annotations.html#dataprovider

使用する場面

上記の通り、テストメソッドに対して複数の引数を渡せるため、
「同一のテストメソッドに対して異なる複数の値を使用したい」時に便利です。

具体的には、例えばユーザー情報のパラメータチェックの処理があるとして「ログインIDが必須」だとします。
この時に

・null も 空文字 も異常系として弾く
・レスポンスパラメータは同じ(同じエラーレスポンスになる)

という場合に、
厳密にいうとテストケースは分かれますが、テストに必要な差分はログインIDの「null」か「空文字」かとなります。
こういったテストの実装時に役立つと思います。

という訳で、文字だけだと伝わりづらいと思いますので、以降で実際にテストコードを書いてみようと思います。

使い方

実際に書いてみる

ひとまず DataProvider を使用して簡単なテストコードを書いてみました。

DataProvider で設定した複数の値(今回は 空文字 と null)がテストメソッドの引数から取得でき、最低限テストを通過するかを見てみたいと思います。


namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Testing\Assert;

class DataProviderSampleTest extends TestCase
{
    /**
     * 異常系:ログインIDの指定がない場合のテスト
     * @param string $invalidLoginId
     * @dataProvider invalidLoginIds
     */
    public function testInvalidLoginId($invalidLoginId): void
    {
        Assert::assertEmpty($invalidLoginId);
    }

    /**
     * ログインIDの異常系テストデータ
     *
     * @return array
     */
    public static function invalidLoginIds(): array
    {
        return [
            [''],
            [null],
        ];
    }
}

実装のポイントは以下となります。

  1. テストメソッドに @dataProvider のコメントを付与する事で invalidLoginIds() を DataProvider として使用する事ができる
  2. invalidLoginIds() は配列を返却しているが、配列内の要素も([''] と [null] のように)配列で記述する必要がある
  3. testInvalidLoginId() の引数は $invalidLoginId としているが、自由に決められる(単数形にしたという意図ではありません。)

テストの実行結果確認

無事にテストが通っている事が確認できました。

また、実際に任意の値「株式会社ビヨンド」を設定し、デバッグ関数(dd())を使用したところ、意図した文字列が $invalidLoginId に格納されていることも確認できました。

もっと実用的な使い方

ここまでは DataProvider を使って、ひとまず最低限のテストコードを書きました。
ただ、上記コードは利便性に欠けるため、もう少し実用的な使い方もあわせてご紹介させていただきます。

以下が変更したコードとなります。

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Testing\Assert;

class DataProviderSampleTest extends TestCase
{
    /**
     * ログインIDの文字列確認テスト
     * @param string $loginId ログインID文字列
     * @param bool $isEmpty empty() の期待値
     * @dataProvider loginIds
     */
    public function testLoginId($loginId, $isEmpty): void
    {
        Assert::assertSame($isEmpty, empty($loginId));
    }

    /**
     * ログインIDの文字列のテストデータ
     *
     * @return array
     */
    public static function loginIds(): array
    {
        return [
            'null は Empty であること' => [null, true],
            '空文字 は Empty であること' => ['', true],
            'testLoginId は Empty ではないこと' => ['testLoginId', false],
        ];
    }
}

主な変更点は以下となります。

  1. テストデータの各要素にキーを指定する(キーにテストケースや何の値かを指定する事で実行結果が見やすくなります。以降で実行結果を添付します。)
  2. 配列に複数の要素を指定する(上記例ではログインIDの文字列と、アサーション実行時の期待値(bool)を指定しています。)
  3. テストメソッドの引数で、データプロバイダで指定された複数の値を受け取る

再度実行結果を確認

改めてテストの実行結果を確認します。

無事テストが通過しました。
先程ご紹介したようにキーを指定することで、どのテストが通過したかが分かりやすくなったかと思います。
また、期待値となる bool も渡すようにした事で、正常系・異常系を含めた汎用性の高いテストコードになりました。

個人的な所感

率直に、DRY なコードを書いていくために便利な機能だと思いました。
テストコードをよりシンプルに少量で書ける良い手段だと感じたため、今後の実装にも活かしていきたいと思います。

また、若干話が逸れますが、今回 DataProvider を調べるきっかけとして、
他言語のフレームワークで「テストに使う値だけ変えてループ実行したい」ケースがあり、『じゃあ、PHPUnit にもそういう感じの機能あるよね...!』と思い立った背景があります。
言語やフレームワークを超えて実装手段なり手札を増やしていく事は非常に有益だと再認識する良い機会となりました。
他にもまだ触ったことのないアノテーションがあるため、引き続き試してみようと思います。

今回の記事は以上となります!
最後までお読みいただき、ありがとうございました!
ではまた!

Webシステム / アプリ開発なら
(サービスページはコチラ)

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
4
読み込み中...
4 票, 平均: 1.00 / 14
3,004
X facebook はてなブックマーク pocket

この記事をかいた人

About the author

福井 浩人

2020年6月にビヨンドに入社。システム開発部 (横浜オフィス) にて勤務。
業務ではPHPを中心に、ゲームAPIやWebシステムの開発、Shopifyプライベートアプリの開発を担当。
洋楽を主として音楽全般が好きで趣味でギターを弾いている。好きなTV番組は、「探偵!ナイトスクープ」「出没!アド街ック天国」。