はじめに
Laravel 6 。ファイルを扱うシンプルな CRUD API の例を作った (今後 Dropzon.js を試すために) – oki2a24 の続きで、バリデーションとそのテストを作りました。
コード。フォームリクエストクラスとそのテスト
フォームリクエストクラスの laravel/app/Http/Requests/Api/FileStoreRequest.php
です。
バリデーションルールは次としました。
- required 。今回の例では、ファイル以外の項目はリクエストボディに存在しないため、必須としました。ファイルの添付がオプションである場合は nullalbe にするなど適宜変更となると思います。
- image 。 file では広すぎで、 mimetypes や mimes では面倒と感じましたので image としました。
- max:2000 。最大 2000 キロバイト、つまりほぼ 2 メガバイトとしました。
<?php
namespace App\Http\Requests\Api;
use Illuminate\Foundation\Http\FormRequest;
class FileStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'file' => 'required|image|max:2000',
];
}
}
フォームリクエストクラスのテストクラスの laravel/tests/Feature/FileStoreRequestTest.php
です。
テスト用のダミーファイルについては、 ファイルアップロードのテスト – HTTPテスト 6.x Laravel を参考にしました。
<?php
namespace Tests\Feature;
use App\Http\Requests\Api\FileStoreRequest;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class FileStoreRequestTest extends TestCase
{
/**
* @test
* @return void
*/
public function 必須エラーとなること()
{
// 準備
$data = [
'file' => null,
];
// 実行
$validator = Validator::make($data, (new FileStoreRequest())->rules());
// 確認。成否
$this->assertTrue($validator->fails());
// 確認。失敗内容
$this->assertEquals([
'file' => ['Required' => [],],
], $validator->failed());
}
/**
* @test
* @return void
*/
public function ファイルが画像ではない時にエラーとなること()
{
// 準備
Storage::fake();
$file = UploadedFile::fake()->create('document.pdf');
$data = [
'file' => $file,
];
// 実行
$validator = Validator::make($data, (new FileStoreRequest())->rules());
// 確認。成否
$this->assertTrue($validator->fails());
// 確認。失敗内容
$this->assertEquals([
'file' => ['Image' => [],],
], $validator->failed());
}
/**
* @test
* @return void
*/
public function 最大サイズエラーとなること()
{
// 準備
Storage::fake();
$file = UploadedFile::fake()->image('document.jpg')->size(2001);
$data = [
'file' => $file,
];
// 実行
$validator = Validator::make($data, (new FileStoreRequest())->rules());
// 確認。成否
$this->assertTrue($validator->fails());
// 確認。失敗内容
$this->assertEquals([
'file' => ['Max' => [2000],],
], $validator->failed());
}
}
コード。その他。
フォームリクエストクラスを使うようにしたコントローラクラスの laravel/app/Http/Controllers/Api/FileController.php
です。差分のみを示します。
アクションの引数をフォームリクエストクラスに変更するだけです。コントローラのテストクラスも、成功時のパターンの観点でのみのテストですのでコントローラのテストクラスの変更の必要はありません。もしエラーのパターンもコントローラのテストで行っている場合は、おそらく変更が必要となると思います。
$ git diff laravel/app/Http/Controllers/Api/FileController.php
diff --git a/laravel/app/Http/Controllers/Api/FileController.php b/laravel/app/Http/Controllers/Api/FileController.php
index 5564da7..e98da0e 100644
--- a/laravel/app/Http/Controllers/Api/FileController.php
+++ b/laravel/app/Http/Controllers/Api/FileController.php
@@ -3,10 +3,10 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
+use App\Http\Requests\Api\FileStoreRequest;
use App\Http\Resources\File as FileResource;
use App\Models\File;
use Illuminate\Http\JsonResponse;
-use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
@@ -26,10 +26,10 @@ class FileController extends Controller
/**
* Store a newly created resource in storage.
*
- * @param \Illuminate\Http\Request $request
+ * @param FileStoreRequest $request
* @return FileResource
*/
- public function store(Request $request): FileResource
+ public function store(FileStoreRequest $request): FileResource
{
$file = $request->file('file');
$path = $file->store('files');
@@ -56,11 +56,11 @@ class FileController extends Controller
/**
* Update the specified resource in storage.
*
- * @param \Illuminate\Http\Request $request
+ * @param FileStoreRequest $request
* @param File $file
* @return FileResource
*/
- public function update(Request $request, File $file): FileResource
+ public function update(FileStoreRequest $request, File $file): FileResource
{
$filePathToBeDeleted = $file->path;
$
おわりに
ファイルアップロードは文字列を POST するのと勝手が異なりますので、バリデーションする時も少しもたついてしまいます。わかってしまえば、または思い出してしまえば、どうってことはありませんので、そのきっかけとするために、今回投稿いたしました。
以上です。