单元测试 Laravel 的 FormRequest

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36978147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:42:41  来源:igfitidea点击:

Unit Test Laravel's FormRequest

phplaravelunit-testingrequestlaravel-5.2

提问by Dov Benyomin Sohacheski

I am trying to unit test various custom FormRequestinputs. I found solutions that:

我正在尝试对各种自定义FormRequest输入进行单元测试。我找到了以下解决方案:

  1. Suggest using the $this->call(…)method and assert the responsewith the expected value (link to answer). This is overkill, because it creates a direct dependency on Routingand Controllers.

  2. Taylor's test, from the Laravel Frameworkfound intests/Foundation/FoundationFormRequestTest.php. There is a lot of mocking and overhead done there.

  1. 建议使用该$this->call(…)方法并response使用预期值断言(链接到答案)。这有点矫枉过正,因为它直接依赖RoutingControllers

  2. Taylor 的测试,来自Laravel Framework中的tests/Foundation/FoundationFormRequestTest.php. 那里有很多嘲笑和开销。

I am looking for a solution where I can unit test individual field inputs against the rules (independent of other fields in the same request).

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

Sample 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',
    ];
}

Desired Test:

所需测试:

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

   // assertTrue, required
   // ...

   // assertFalse, between
   // ...
}

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

How can I unit test (assert)each validation rule of every field in isolation and individually?

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

回答by Dov Benyomin Sohacheski

I found a good solution on Laracastand added some customization to the mix.

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

The Code

编码

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

Update

更新

There is an e2eapproach to the same problem. You can POSTthe data to be checked to the route in question and then see if the response contains session errors.

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

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

回答by Yevgeniy Afanasyev

Friends, please, make the unit-test properly, after all, it is not only rulesyou are testing here, the validationDataand withValidatorfunctions may be there too.

朋友们,请好好做单元测试,毕竟rules这里不只是你在测试,函数validationDatawithValidator函数也可能在那里。

This is how it should be done:

应该这样做:

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


}