[Laravel][テストコード]FormRequestのバリデーションのテストコードの書き方
こんにちは、かっちゃんです。
今回は簡単なFormRequestのバリデーションのテストコードを書いていこうと思います。 まずは以下の様なFormRequestのクラスを作成します。
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
/**
* Class StorePost
* @package App\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に書くとテストクラスがスッキリして見やすくなります。
最後に
皆さんものより良いテストライフを過ごす為に、少しでも参考になればなと思います。ありがとうございました。