開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Laravel >
  5. [Laravel][テストコード]FormRequestのバリデーションのテストコードの書き方
no-image

[Laravel][テストコード]FormRequestのバリデーションのテストコードの書き方

こんにちは、かっちゃんです。
今回は簡単なFormRequestのバリデーションのテストコードを書いていこうと思います。 まずは以下の様なFormRequestのクラスを作成します。

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

/**
 * Class StorePost
 * @package Beenos\Corazon\Http\Requests
 */
class StorePost extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize(): bool
    {
        return true;
    }

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

    /**
     * @return string[]
     */
    public function attributes(): array
    {
        return [
            'name' => '名前',
        ];
    }
}
あまりプロパティを増やすとこのあと紹介するテストコードが長くなりますので、今回は上記の様にかなり少なくプロパティを設定しました。
次にテストコードを作成していきます。
namespace Tests\Feature;

use Illuminate\Foundation\Testing\TestResponse;
use Tests\TestCase;

/**
 * Class ValidationTest
 * @package Tests\Feature
 */
class ValidationTest extends TestCase
{
    /**
     * @testdox 不正なリクエストに対して正常にバリデーションが動作している
     * @param array $payload
     * @param array $errorMessage
     * @dataProvider dataProvideInvalidPayload
     */
    public function testPostInvalidRequestStatusCode422(array $payload, array $errorMessage): void
    {
        $response = $this->postRequest($payload);
        $response->assertStatus(422);
        $response->assertJsonValidationErrors($errorMessage);
    }

    /**
     * @testdox 正常なリクエストに対して正常にバリデーションが動作している
     */
    public function testPostValidRequestStatusCode200(): void
    {
        $response = $this->postRequest();
        $response->assertStatus(200);
    }

    /**
     * @param array|null $payload
     * @return TestResponse
     */
    private function postRequest(array $payload = null): TestResponse
    {
        return $this->json(
            'post',
            "/test",
            $payload ?? $this->basePayload()
        );
    }

    /**
     * @return iterable
     */
    public function dataProvideInvalidPayload(): iterable
    {
        yield '名前が文字列じゃない' => [
            'payload' => array_merge(
                $this->basePayload(),
                [
                    'name' => true,
                ]
            ),
            'errorMessage' => [
                'name' => '名前は文字列を指定してください。',
            ]
        ];

        yield '名前が65文字以上' => [
            'payload' => array_merge(
                $this->basePayload(),
                [
                    'name' => str_repeat('a', 65),
                ]
            ),
            'errorMessage' => [
                'name' => '名前は、64文字以下で指定してください。',
            ]
        ];

        yield '名前がnull' => [
            'payload' => array_merge(
                $this->basePayload(),
                [
                    'name' => null,
                ]
            ),
            'errorMessage' => [
                'name' => '名前は必ず指定してください。',
            ]
        ];
    }

    /**
     * @return array
     */
    private function basePayload(): array
    {
        return [
            'name' => 'テスト太郎',
        ];
    }
}


今回のテストコードの書き方でポイントになってくるのは以下3点です。

色々なパターンのリクエストを送る為のdataProviderを作成

こちらを行う事により、どの様な条件の元でバリデーションテストを行っているのかが見て分かります。
正常なリクエストをメソッドで取得することにより、バリデーションエラーを起こしたいプロパティのみを修正すれば良いのも楽ですね。

 ステータスコードだけではなく、エラーメッセージも比較する

ステータスコードだけでバリデーションエラーの確認をしてしまうと、何が原因でバリデーションエラーが起こっているのかまではテストが出来ていないので、テストとしては不十分だと思います。
エラーメッセージも比較してあげる事により、意図したエラーが起こっているかがテスト出来ます。
今回は少ないプロパティのFormRequestクラスのテストでしたが、複雑になってくると意図していないエラーが発生してバグの早期発見にも繋がりますので、テストとしての役割を果たしてくれますね。

dataProviderにarrayではなくGeneratorを使う

dataProviderをarrayでは無くGeneratorを使う事によりメモリの節約になります。
arrayですと膨大な量のデータを処理するとメモリ不足で落ちてしまう事がありますが、Generatorだとその様な心配はありません。


今回は少ないプロパティのFormRequestクラスのテストでしたが、より複雑でより多くのルールを持つFormRequestクラスのテストを行うと、正常なリクエストを取得するメソッドとdataProviderに設定しているメソッドがかなり大きくなりますので、traitを作成してこららのメソッドをtraitに書くとテストクラスがスッキリして見やすくなります。

最後に

皆さんものより良いテストライフを過ごす為に、少しでも参考になればなと思います。
ありがとうございました。
TOPに戻る