单元测试 Laravel 的 FormRequest

我正在尝试对各种自定义输入进行单元测试。我发现的解决方案是:FormRequest

  1. 建议使用该方法并使用预期值断言 (链接到答案)。这是矫枉过正,因为它会直接依赖于路由控制器$this->call(…)response

  2. 泰勒的测试,来自 Laravel 框架,在 .那里有很多嘲笑和开销。tests/Foundation/FoundationFormRequestTest.php

我正在寻找一种解决方案,我可以在其中根据规则对单个字段输入进行单元测试(独立于同一请求中的其他字段)。

示例表单请求:

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()
{
    // ...
}

如何单独和单独地对每个字段的每个验证规则进行单元测试(断言)


答案 1

我在Laracast上找到了一个很好的解决方案,并在混音中添加了一些自定义。

守则

/**
 * Test first_name validation rules
 * 
 * @return void
 */
public function test_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'));
}

/**
 * Check a field and value against validation rule
 * 
 * @param string $field
 * @param mixed $value
 * @return bool
 */
protected function validateField(string $field, $value): bool
{
    return $this->validator->make(
        [$field => $value],
        [$field => $this->rules[$field]]
    )->passes();
}

/**
 * Set up operations
 * 
 * @return void
 */
public function setUp(): void
{
    parent::setUp();

    $this->rules     = (new UserStoreRequest())->rules();
    $this->validator = $this->app['validator'];
}

更新

对于同样的问题,也有一种e2e方法。您可以将要检查的数据发布到有问题的路由,然后查看响应是否包含会话错误

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

答案 2

朋友们,请把单元测试做好,毕竟,你在这里测试的不仅仅是你,和功能可能也在那里。rulesvalidationDatawithValidator

这是应该如何完成的:

<?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));
    }


}

推荐