LoginSignup
0
0

More than 1 year has passed since last update.

PHPUnitで行うValidationのテスト

Posted at

実務でPHPUnitを使ってValidationの異常系テストコードを追加することがあったので
そこで得られた知識をアウトプットします!

仮に以下のRequestファイルがあったとします。

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required|max:100',
            'email' => 'required'
        ];
    }
}

ユーザー名に必須チェック最大文字数
メールアドレスに必須チェック
のバリデーションがついています。

テストコードの作成

バリデーションのチェックは、一つ一つチェックしていくこともできますが、
コードの保守性を考え、データプロバイダーを使用しました。

tests/Unit/Requests/UserRequestTest.php
<?php

class UserRequestTest extends TestCase
{
	/* *
	 * バリデーションテスト
	 *
	 * @param array 項目名の配列
	 * @param array 値の配列
	 * @param 期待値(true:バリデーションOK、false:バリデーションNG)
	 *
	 * 使用するデータプロバイダーを記述
	 * @dataProvider dataprovider
	 */
	public function testBasicTest(array $keys, array $values, bool $expect): void
	{
		//入力項目の配列($keys)と値の配列($values)から、連想配列を生成する
		$dataList = array_combine($keys, $values);

		//先ほど作成したUserRequestのオブジェクトを作成
		$request  = new UserRequest();

		//ユーザーリクエストで定義したルールを取得
		$rules    = $request->rules();

		//Validatorファサードでバリデーターのインスタンスを取得、その際に入力情報とバリデーションルールを引数で渡す
		$validator = Validator::make($dataList, $rules);

		//入力情報がバリデーショルールを満たしている場合はtrue、満たしていな場合はfalseが返る
		$result    = $validator->passes();

		//期待値($expect)と結果($result)を比較
		$this->assertEquals($expect, $result);
	}

	/**
	 * データプロバイダ
	 *
	 * @return データプロバイダ
	 *
	 * @dataProvider dataprovider
	 */
	public function dataprovider(): array
	{
		return [
			'ユーザー名が必須エラー' => [
				['name', 'email'],
				[null, 'test@example.com'],
				false
			],
			'ユーザー名が100文字超えているエラー' => [
				['name', 'email'],
				[str_repeat('あ', 101),'test@example.com'],
				false
			],
			'メールアドレスが必須エラー' => [
				['name', 'email'],
				['test', null],
				false
			],
		];
	}
}

今回は異常系のテストだけを記述しましたが、
このように記述することで、複数のバリデーションでも見やすく、変更がしやすいテストを記述することができます!

余談

プロバイダーメソッドを使用してつまづいた実装をメモで残しておきます。

つまづいた点①

ネストされた値をどうチェックするか
user.nameのようにドットで項目が記載されている

仮に以下のRequestファイルがあったとします。

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            
            'user.name' => 'required|max:100',
            'user.email' => 'required'
        ];
    }
}

今まで通りにデータプロバイダーを作成しても、正しい動きになりません。
実際に何時間も悩みました...

上記の場合は、以下のように書くと正しく動きます!

tests/Unit/Requests/UserRequestTest.php
/**
	 * データプロバイダ
	 *
	 * @return データプロバイダ
	 *
	 * @dataProvider dataprovider
	 */
	public function dataprovider(): array
	{
		return [
			'ユーザー名が必須エラー' => [
				['user',],
				[['name' => null], ['email' => 'test@example.com']],
				false
			],
			'ユーザー名が100文字超えているエラー' => [
				['name', 'email'],
				[['name' => str_repeat('あ', 101)], ['email' => 'test@example.com']],
				false
			],
			'メールアドレスが必須エラー' => [
				['name', 'email'],
				[['name' => 'test'], ['email' => null]],
				false
			],
		];
	}

つまづいた点②

ログインユーザーIDが使われている

app/Http/Requests/UserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'id' => $this->user()->id,
            'name' => 'required|max:100',
            'email' => 'required'
        ];
    }
}

上記の例は、認証などが関わっており、そこで使用されていました。

この場合も、データプロバイダーに

Auth::id()

と書いても正しい動きにはなりません。
このような場合は、以下のように書く必要があります。

tests/Unit/Requests/UserRequestTest.php
<?php

class UserRequestTest extends TestCase
{
	/* *
	 * バリデーションテスト
	 *
	 * @param array 項目名の配列
	 * @param array 値の配列
	 * @param 期待値(true:バリデーションOK、false:バリデーションNG)
	 *
	 * 使用するデータプロバイダーを記述
	 * @dataProvider dataprovider
	 */
	public function testBasicTest(array $keys, array $values, bool $expect): void
	{
		//入力項目の配列($keys)と値の配列($values)から、連想配列を生成する
		$dataList = array_combine($keys, $values);

		//先ほど作成したUserRequestのオブジェクトを作成
		$request  = new UserRequest();

        // setUserResolverを呼ぶ
        $request = setUserResolver(function () use ($user) {
            return $user;
        }

		//ユーザーリクエストで定義したルールを取得
		$rules    = $request->rules();

		//Validatorファサードでバリデーターのインスタンスを取得、その際に入力情報とバリデーションルールを引数で渡す
		$validator = Validator::make($dataList, $rules);

		//入力情報がバリデーショルールを満たしている場合はtrue、満たしていな場合はfalseが返る
		$result    = $validator->passes();

		//期待値($expect)と結果($result)を比較
		$this->assertEquals($expect, $result);
	}

}

のようにしてあげると正しい挙動になる。

あくまで、自分の学習のメモとして残しているので、参考程度に見ていただけると幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0