もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

LaravelのFormRequestのテストを書く

こんばんは

今回もLaravelネタです。

FormRequestはLaravel使っているうえで結構使うのですが、それのテストって書いてなかったなぁと思ったので、書いてみようと思いました。

本題

まずこんな感じのFormRequest作ります。

UserRegisterRequest.php

<?php

namespace App\Requests;

use App\Requests\Rules\UserStatusExistsRule;
use Illuminate\Foundation\Http\FormRequest;

class UserRegisterRequest extends FormRequest
{
    /**
     * @return bool
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * @return array
     */
    public function rules(): array
    {
        return [
            'name'    => 'required|string',
            'status'   => ['required', 'numeric', new UserStatusExistsRule()],
        ];
    }
}

name, status を リクエストでもらってそれを検証するようなかんたんな形です。

ちなみに、 UserStatusExistsRule は以下のような形です。

UserStatusExistsRule.php

<?php

namespace App\Requests\Rules;

use App\Domain\ValueObject\UserStatus;
use Illuminate\Contracts\Validation\Rule;

class UserStatusExistsRule implements Rule
{
    /**
     * @param $attribute
     * @param $value
     * @return bool
     */
    public function passes($attribute, $value): bool
    {
        try {
            new UserStatus((int)$value)); // 1 or 2でないとExceptionが発生する
            $result = true;
        } catch (\Throwable $e) {
            $result = false;
        }
        return $result;
    }
}

これに対してのテストコードは以下

UserRegisterRequestTest.php

<?php

namespace Tests\Requests;

use App\Requests\UserRegisterRequest;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\Request;
use Tests\TestCase;

class UserRegisterRequestTest extends TestCase
{
    /**
     * @test
     * @dataProvider validationDataProvider
     * @param array $parameters
     * @param bool $expected
     * @param string $message
     * @return void
     */
    public function validation(array $parameters, bool $expected, string $message): void
    {
        $request = new UserRegisterRequest();
        $validator = Validator::make($parameters, $request->rules(), $request->message());
        self::assertSame($expected, $validator->passes(), $message);
    }

    /**
     * @return array
     */
    public function validationDataProvider(): array
    {
        return [
            [
                [],
                false,
                'リクエストが送られていないのでfalse'
            ],
            [
                ['name' => 'aa'],
                false,
                'statusが送られていないのでfalse'
            ],
            [
                ['status' => '1'],
                false,
                'nameが送られていないのでfalse'
            ],
            [
                ['name' => 'ああああ', 'status' => 'ああ'],
                false,
                'statusが数値型ではないのでfalse'
            ],
            [
                ['name' => 'ああああ', 'status' => '1000'],
                false,
                'statusが許された値ではないのでfalse'
            ],
            [
                ['name' => 'ああああ', 'status' => '1'],
                true,
                '成功パターン'
            ],
        ];
    }
}

作った際のメリットとしては、以下の2点かなと思いました。

  • リクエストの全体を網羅的にかんたんにテストできる。
  • 上記ができるのでControllerのFeatureテストを薄く出来る。

デメリットは書くのめんどくせーと思うくらいですかね。。。

もっとやりやすいテスト方法あれば教えて下さい!

終わりに

最近やっと本読めるような時間ができてきました。

そういえば、Web+DB Press vol.127 のリファクタリングの話すごくためになりました。

特に凝集度の話勉強になりました。

読んでない方はぜひ