Laravelでカスタムバリデーションのユニットテストをする方法
メモ PHPLaravel

Laravelでカスタムバリデーションのユニットテストをする方法

2022.03.25

LaravelではIlluminate\Contracts\Validation\Ruleを継承したクラスを用いてカスタムなバリデーションを作成することができます。そしてサービスプロバイダに登録することで、FormRequestで文字列で指定することでリクエストのバリデーションを拡張できます。

ただしこの様な独自コードはきちんとユニットテストをすることが大切です。Laravelではこのカスタムバリデーションを簡単にユニットテストをすることができます。

サンプルのバリデーション

とりあえず以下の様な郵便番号のバリデーションを作成したとします。7桁のハイフンなしの数字が郵便番号の形式とします。

namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;

class Zipcode implements Rule{

    public function passes($attribute, $value)
    {
        return preg_match('/^[0-9]{3}-?[0-9]{4}$/', $value);
    }

    public function message(){
        return '郵便番号は7桁の半角数字で入力してください。';
    }
}

ユニットテストファイルを作成

ひとまず tests/Unit/Rules.php というものを作成します。

Rules.php
namespace Tests\Unit;

use App\Rules\Zipcode;
use Illuminate\Foundation\Testing\TestCase;
use Tests\CreatesApplication;
use Illuminate\Support\Facades\Validator;
use \Illuminate\Validation\ValidationException;

class Rules extends TestCase{
    use CreatesApplication;

    public function test_zipcode_validation(){
        $tests = [
            '1234567'=>true,
            '0012344'=>true,
            '0012340'=>true,
            '12345678'=>false,
            '123456'=>false,
            '1234 56'=>false,
            '1234a56'=>false,
            '1234_56'=>false,
        ];
        foreach($tests as $key => $condition){
            try{
                Validator::make(['test'=>$key],[
                    'test'=> new Zipcode()
                ])->validate();
                $this->assertTrue($condition===true);
            }catch(ValidationException $e){
                $this->assertFalse($condition);
            }
        }
    }
}

バリデーションテストでは正しい形式は正しいと判断(ポジティブテスト)し、間違っているものは間違っていると判断(ネガティブテスト)できているかをテストします。 もしも正しいのに間違っていると判断したり、間違っているのに正しいとなったらテストが失敗する様になっています。

ここでバリデーションテストの詳細を解説します。

バリデーションのインスタンスを作成

最初にテストしたいバリデーションのインスタンス、そしてバリデーターインスタンスを作成します。

Validator::make(['test'=>$key],[
    'test'=> new Zipcode()
])->validate();

Validatorではmake()を使用して第一引数に、バリデーションをする値とキーを設定します。第二引数にはバリデーションのキーとバリデーションインスタンスを指定します。

いろんなパターンをテストする

いろいろなパターンをテストするため以下の様に配列でテストパターンと予期する正誤を設定します。Trueはバリデーション通過で、Falseはバリデーション違反(間違った形式)であることを示します。

$tests = [
    '1234567'=>true,
    '0012344'=>true,
    '0012340'=>true,
    '12345678'=>false,
    '123456'=>false,
    '1234 56'=>false,
    '1234a56'=>false,
    '1234_56'=>false,
];

そしてforeachでそれぞれチェックします。

foreach($tests as $key => $condition){
    try{
        Validator::make(['test'=>$key],[
            'test'=> new Zipcode()
        ])->validate();
        $this->assertTrue($condition===true);
    }catch(ValidationException $e){
        $this->assertFalse($condition);
    }
}

validate()メソッドは失敗するとValidationException を投げます。そのため例外処理でValidationException をキャッチします。正しい形式を正しいと判断できれば$this->assertTrue($condition===true);となり、まちがった形を間違っていると判断できればキャッチして$this->assertFalse($condition);でアサートされます。

php artisan test 

にてテストを行い問題なければそのまま通過します。テストは以上の方法でいろんなパターンをテストできます。パターンは思いついたものを配列に書いてもいいですし、プログラム的に大量に配列を生成してもいいかもしれません。まとめると

  • バリデーションインスタンスを作成
  • ValidationExceptionを用いて間違っている形を識別
  • バリデーション対象の値が正誤かどうかはassertTrueassertFalseで正しく判断できているかをアサート

こんな感じです。私はこのテストで結構救われたので、バリデーションを作った時は必ずユニットテストをしましょう。

Copyright © 2021 jun. All rights reserved.