web-dev-qa-db-ja.com

ユニットテストLaravelのFormRequest

さまざまなカスタムFormRequest入力をユニットテストしようとしています。私は次の解決策を見つけました:

  1. $this->call(…)メソッドの使用を提案し、期待値 (回答へのリンク) を使用してresponseをアサートします。 RoutingおよびControllersに直接依存するため、これはやりすぎです。

  2. Laravel Frameworkからのテイラーのテスト found /tests/Foundation/FoundationFormRequestTest.php。そこには多くのモックとオーバーヘッドがあります。

ルールに対して個々のフィールド入力をユニットテストできるソリューションを探しています(同じリクエスト内の他のフィールドから独立しています)

サンプルFormRequest:

public function rules()
{
    return [
        'first_name' => 'required|between:2,50|alpha',
        'last_name'  => 'required|between:2,50|alpha',
        'email'      => 'required|email|unique:users,email',
        'username'   => 'required|between:6,50|alpha_num|unique:users,username',
        'password'   => 'required|between:8,50|alpha_num|confirmed',
    ];
}

必要なテスト:

public function testFirstNameField()
{
   // assertFalse, required
   // ...

   // assertTrue, required
   // ...

   // assertFalse, between
   // ...
}

public function testLastNameField()
{
    // ...
}

どのようにすれば単体テスト(assert)で各フィールドの各検証ルールを単体テストできますか?

Laracast で良い解決策を見つけ、ミックスにいくつかのカスタマイズを追加しました。

コード

public function setUp()
{
    parent::setUp();
    $this->rules     = (new UserStoreRequest())->rules();
    $this->validator = $this->app['validator'];
}

/** @test */
public function valid_first_name()
{
    $this->assertTrue($this->validateField('first_name', 'jon'));
    $this->assertTrue($this->validateField('first_name', 'jo'));
    $this->assertFalse($this->validateField('first_name', 'j'));
    $this->assertFalse($this->validateField('first_name', ''));
    $this->assertFalse($this->validateField('first_name', '1'));
    $this->assertFalse($this->validateField('first_name', 'jon1'));
}

protected function getFieldValidator($field, $value)
{
    return $this->validator->make(
        [$field => $value], 
        [$field => $this->rules[$field]]
    );
}

protected function validateField($field, $value)
{
    return $this->getFieldValidator($field, $value)->passes();
}

更新

同じ問題に対してe2eアプローチがあります。確認するデータを[〜#〜] [〜#〜]対象のルートに送信し、応答にセッションが含まれているかどうかを確認できますエラー

$response = $this->json('POST', 
    '/route_in_question', 
    ['first_name' => 'S']
);
$response->assertSessionHasErrors(['first_name');

フレンド、ユニットテストを正しく行ってください。結局のところ、ここでテストしているのはrulesだけではなく、validationData関数とwithValidator関数も存在する可能性があります。

これはどのように行われるべきかです:

<?php

namespace Tests\Unit;

use App\Http\Requests\AddressesRequest;
use App\Models\Country;
use Faker\Factory as FakerFactory;
use Illuminate\Routing\Redirector;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
use function app;
use function str_random;

class AddressesRequestTest extends TestCase
{


    public function test_AddressesRequest_empty()
    {
        try {
            //app(AddressesRequest::class);
            $request = new AddressesRequest([]);
            $request
                ->setContainer(app())
                ->setRedirector(app(Redirector::class))
                ->validateResolved();
        } catch (ValidationException $ex) {

        }
        //\Log::debug(print_r($ex->errors(), true));

        $this->assertTrue(isset($ex));
        $this->assertTrue(array_key_exists('the_address', $ex->errors()));
        $this->assertTrue(array_key_exists('the_address.billing', $ex->errors()));
    }


    public function test_AddressesRequest_success_billing_only()
    {
        $faker = FakerFactory::create();
        $param = [
            'the_address' => [
                'billing' => [
                    'Zip'        => $faker->postcode,
                    'phone'      => $faker->phoneNumber,
                    'country_id' => $faker->numberBetween(1, Country::count()),
                    'state'      => $faker->state,
                    'state_code' => str_random(2),
                    'city'       => $faker->city,
                    'address'    => $faker->buildingNumber . ' ' . $faker->streetName,
                    'suite'      => $faker->secondaryAddress,
                ]
            ]
        ];
        try {
            //app(AddressesRequest::class);
            $request = new AddressesRequest($param);
            $request
                ->setContainer(app())
                ->setRedirector(app(Redirector::class))
                ->validateResolved();
        } catch (ValidationException $ex) {

        }

        $this->assertFalse(isset($ex));
    }


}
0