Laravelフォームリクエストのテスト
私はどのようにRolavelでフォームのリクエストをテストする必要があります決定するために苦労していた.具体的には、検証をテストしたいと思いました.私は迅速なGoogle検索を行いました、そして、それはそれをする複数の方法があるようです.つのブログ記事は、すべてのうち立っていたA guide to unit testing Laravel Form Requests in a different way そば@daaaan . 彼は、統合テストを書く代わりに、例えば
これは確かに私が試してみたかった何かだった、過去に私は、いくつかのテストメソッド、各テスト個々のリクエスト属性を要求を形成していたし、多くのコードの重複があった.
Danは以下を示唆します
これはどうやって動くの?
it_fails_validation_without_title
phpunitの@ dataprovidersの助けを借りて単体テストを使うべきです.これは確かに私が試してみたかった何かだった、過去に私は、いくつかのテストメソッド、各テスト個々のリクエスト属性を要求を形成していたし、多くのコードの重複があった.
Danは以下を示唆します
<?php
namespace Tests\Feature\App\Http\Requests;
use App\Http\Requests\SaveProductRequest;
use Faker\Factory;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class SaveProductRequestTest extends TestCase
{
use RefreshDatabase;
/** @var \App\Http\Requests\SaveProductRequest */
private $rules;
/** @var \Illuminate\Validation\Validator */
private $validator;
public function setUp(): void
{
parent::setUp();
$this->validator = app()->get('validator');
$this->rules = (new SaveProductRequest())->rules();
}
public function validationProvider()
{
/* WithFaker trait doesn't work in the dataProvider */
$faker = Factory::create( Factory::DEFAULT_LOCALE);
return [
'request_should_fail_when_no_title_is_provided' => [
'passed' => false,
'data' => [
'price' => $faker->numberBetween(1, 50)
]
],
'request_should_fail_when_no_price_is_provided' => [
'passed' => false,
'data' => [
'title' => $faker->word()
]
],
'request_should_fail_when_title_has_more_than_50_characters' => [
'passed' => false,
'data' => [
'title' => $faker->paragraph()
]
],
'request_should_pass_when_data_is_provided' => [
'passed' => true,
'data' => [
'title' => $faker->word(),
'price' => $faker->numberBetween(1, 50)
]
]
];
}
/**
* @test
* @dataProvider validationProvider
* @param bool $shouldPass
* @param array $mockedRequestData
*/
public function validation_results_as_expected($shouldPass, $mockedRequestData)
{
$this->assertEquals(
$shouldPass,
$this->validate($mockedRequestData)
);
}
protected function validate($mockedRequestData)
{
return $this->validator
->make($mockedRequestData, $this->rules)
->passes();
}
}
これはどうやって動くの?
テストメソッドで配列を提供しています.私たちはこのように多くのテストメソッドを持つことができます、そして、PHPUnitは残りの世話をします.追加@dataProvider
注釈validation_results_as_expected
メソッドは、アサーションが実際に発生する場所です.各項目をループして呼び出しますvalidate
テストケースでのメソッド.このメソッドは順番に呼び出します.validate
on $this->validator
で定義するsetUp
.
問題
今、私は本当にこのアプローチが好きですが、私は実際に私のフォームの要求をテストしていないように感じた.にsetUp
メソッドをフォームリクエストをインスタンス化しますが、検証規則を取得してからLaravelのバリデータに渡すだけです.これはおそらく、ほとんどの場合、単純なデータで動作しますが、私の場合、私はデータ操作をしていましたprepareForValidation
フォームリクエストメソッド.私も、他のチェックをしていましたwithValidator
メソッド.このテストアプローチでは、それらのメソッドは呼び出されません.また、私のフォームリクエストが期待通りに動作するかどうかはわかりません.
解決策?
バリデータを設定する代わりに、実際のフォームリクエストを設定する必要がありましたので、すぐに変更しましたvalidate
以下のようなテストケースでのメソッド
protected function validate($mockedRequestData)
{
return (new CreateRedirectRequest())->...;
}
ちょっと待って.どのような方法を呼びますか.どうやってデータを渡すのですか?それから、私はIlluminate\Foundation\Http\FormRequest
そして、それは広がるように見えますIlluminate\Http\Request
, どちらが順番に広がるかSymfony\Component\HttpFoundation\Request
. さて、フォームリクエストが実際にリクエストを拡張しているように見えます.
それで、私は容器からそれを分解すると思いました.validateメソッドを次のように変更しました.
protected function validate($mockedRequestData)
{
app(CreateRedirectRequest::class);
}
私はテストを実行し、私はすぐにエラーで迎えられた.インマイwithValidator
私はこんな風にやっていました.
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (! $this->parse($this->source)) {
$validator->errors()->add('source', 'Invalid source');
}
});
}
エラーはArgument 1 passed to parse() must be of the type string, null given
. どうやって動くのだろう.まだ検証を呼び出していませんがwithValidator
メソッドは呼ばれています、そして、私はまだそれにデータさえ渡しませんでした.
検査したFormRequest
もう一度クラスを利用しているようですValidatesWhenResolved
インタフェースとValidatesWhenResolvedTrait
特性まあ、それは言うことです.この特性を使用しているオブジェクトがコンテナから解決されるとき、それは呼び出しますprepareForValidation
, これは認証をチェックし、最終的に要求を正しく検証します.
にFormRequestServiceProvider
このコードを見ることができます.
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
$resolved->validateResolved();
});
$this->app->resolving(FormRequest::class, function ($request, $app) {
$request = FormRequest::createFrom($app['request'], $request);
$request->setContainer($app)->setRedirector($app->make(Redirector::class));
});
}
OK、それで、これは後で解決します、私は、ララベルもAを持っていますresolving
コールバックので、解決する前にデータを渡すことができますか?変更しましたvalidate
次のような方法をもう一度行います.
protected function validate($mockedRequestData)
{
$this->app->resolving(CreateRedirectRequest::class, function ($resolved) use ($mockedRequestData){
$resolved->merge($mockedRequestData);
});
try {
app(CreateRedirectRequest::class);
return true;
} catch (ValidationException $e) {
return false;
}
}
私はテストを実行し、彼らはすべて合格します.さて、このテストケースに新しいテストを追加したい場合は、新しい配列項目をデータに追加して渡す必要があるだけです.
では、なぜそれが動作しますか?
Laravelのコンテナがフォームリクエストを解決しているときに動作します
オブジェクトは、$mockedRequestData
配列を返します.
それが正常に解決するならば、我々はすべてのデータが有効であるということを知っていますIlluminate\Validation\ValidationException
, どちらをキャッチしようとします.我々は真か偽かを返すvalidation_results_as_expected
次に、テストケースが通過するかどうかを比較します.また、'セットアップ'はもう必要ありません.
最終語
各リクエスト属性を個別にテストする複数のテストメソッドを記述している場合は、試してみてください.閉じるこの動画はお気に入りから削除されています.私は確かにこのアプローチを好む.
追伸
私はウェブ開発に新しくないが、これは私の最初のブログ記事です.あなたが将来的にこれのようなより多くのブログ柱を読みたいならば、私に続くか、コメントを残して、私はどんなフィードバックまたは質問でも歓迎します.
Reference
この問題について(Laravelフォームリクエストのテスト), 我々は、より多くの情報をここで見つけました
https://dev.to/dsazup/testing-laravel-form-requests-853
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
今、私は本当にこのアプローチが好きですが、私は実際に私のフォームの要求をテストしていないように感じた.に
setUp
メソッドをフォームリクエストをインスタンス化しますが、検証規則を取得してからLaravelのバリデータに渡すだけです.これはおそらく、ほとんどの場合、単純なデータで動作しますが、私の場合、私はデータ操作をしていましたprepareForValidation
フォームリクエストメソッド.私も、他のチェックをしていましたwithValidator
メソッド.このテストアプローチでは、それらのメソッドは呼び出されません.また、私のフォームリクエストが期待通りに動作するかどうかはわかりません.解決策?
バリデータを設定する代わりに、実際のフォームリクエストを設定する必要がありましたので、すぐに変更しましたvalidate
以下のようなテストケースでのメソッド
protected function validate($mockedRequestData)
{
return (new CreateRedirectRequest())->...;
}
ちょっと待って.どのような方法を呼びますか.どうやってデータを渡すのですか?それから、私はIlluminate\Foundation\Http\FormRequest
そして、それは広がるように見えますIlluminate\Http\Request
, どちらが順番に広がるかSymfony\Component\HttpFoundation\Request
. さて、フォームリクエストが実際にリクエストを拡張しているように見えます.
それで、私は容器からそれを分解すると思いました.validateメソッドを次のように変更しました.
protected function validate($mockedRequestData)
{
app(CreateRedirectRequest::class);
}
私はテストを実行し、私はすぐにエラーで迎えられた.インマイwithValidator
私はこんな風にやっていました.
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (! $this->parse($this->source)) {
$validator->errors()->add('source', 'Invalid source');
}
});
}
エラーはArgument 1 passed to parse() must be of the type string, null given
. どうやって動くのだろう.まだ検証を呼び出していませんがwithValidator
メソッドは呼ばれています、そして、私はまだそれにデータさえ渡しませんでした.
検査したFormRequest
もう一度クラスを利用しているようですValidatesWhenResolved
インタフェースとValidatesWhenResolvedTrait
特性まあ、それは言うことです.この特性を使用しているオブジェクトがコンテナから解決されるとき、それは呼び出しますprepareForValidation
, これは認証をチェックし、最終的に要求を正しく検証します.
にFormRequestServiceProvider
このコードを見ることができます.
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
$resolved->validateResolved();
});
$this->app->resolving(FormRequest::class, function ($request, $app) {
$request = FormRequest::createFrom($app['request'], $request);
$request->setContainer($app)->setRedirector($app->make(Redirector::class));
});
}
OK、それで、これは後で解決します、私は、ララベルもAを持っていますresolving
コールバックので、解決する前にデータを渡すことができますか?変更しましたvalidate
次のような方法をもう一度行います.
protected function validate($mockedRequestData)
{
$this->app->resolving(CreateRedirectRequest::class, function ($resolved) use ($mockedRequestData){
$resolved->merge($mockedRequestData);
});
try {
app(CreateRedirectRequest::class);
return true;
} catch (ValidationException $e) {
return false;
}
}
私はテストを実行し、彼らはすべて合格します.さて、このテストケースに新しいテストを追加したい場合は、新しい配列項目をデータに追加して渡す必要があるだけです.
では、なぜそれが動作しますか?
Laravelのコンテナがフォームリクエストを解決しているときに動作します
オブジェクトは、$mockedRequestData
配列を返します.
それが正常に解決するならば、我々はすべてのデータが有効であるということを知っていますIlluminate\Validation\ValidationException
, どちらをキャッチしようとします.我々は真か偽かを返すvalidation_results_as_expected
次に、テストケースが通過するかどうかを比較します.また、'セットアップ'はもう必要ありません.
最終語
各リクエスト属性を個別にテストする複数のテストメソッドを記述している場合は、試してみてください.閉じるこの動画はお気に入りから削除されています.私は確かにこのアプローチを好む.
追伸
私はウェブ開発に新しくないが、これは私の最初のブログ記事です.あなたが将来的にこれのようなより多くのブログ柱を読みたいならば、私に続くか、コメントを残して、私はどんなフィードバックまたは質問でも歓迎します.
Reference
この問題について(Laravelフォームリクエストのテスト), 我々は、より多くの情報をここで見つけました
https://dev.to/dsazup/testing-laravel-form-requests-853
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
protected function validate($mockedRequestData)
{
return (new CreateRedirectRequest())->...;
}
protected function validate($mockedRequestData)
{
app(CreateRedirectRequest::class);
}
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (! $this->parse($this->source)) {
$validator->errors()->add('source', 'Invalid source');
}
});
}
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->app->afterResolving(ValidatesWhenResolved::class, function ($resolved) {
$resolved->validateResolved();
});
$this->app->resolving(FormRequest::class, function ($request, $app) {
$request = FormRequest::createFrom($app['request'], $request);
$request->setContainer($app)->setRedirector($app->make(Redirector::class));
});
}
protected function validate($mockedRequestData)
{
$this->app->resolving(CreateRedirectRequest::class, function ($resolved) use ($mockedRequestData){
$resolved->merge($mockedRequestData);
});
try {
app(CreateRedirectRequest::class);
return true;
} catch (ValidationException $e) {
return false;
}
}
Reference
この問題について(Laravelフォームリクエストのテスト), 我々は、より多くの情報をここで見つけました https://dev.to/dsazup/testing-laravel-form-requests-853テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol