【问题标题】:Laravel 7 empty array validationLaravel 7 空数组验证
【发布时间】:2021-07-02 06:19:27
【问题描述】:

我正在尝试验证 FormRequest 中所需的(可能)空数组。

我使用presentarray 验证规则,因为我希望传递值,但它可能是一个空数组。

问题是我的测试在空字符串(即:'')上失败,告诉我我的请求没有抛出具有该值的预期 ValidationException

我的测试涵盖了给定字段的以下值:

input value expected result test outcome
null error present passed
'a string' error present passed
'' error present failed
123 error present passed
123.456 error present passed
true error present passed
[] error not present passed
['a', 'b'] error not present passed

我如何测试预期的请求参数是否存在,是一个数组并且可能是一个空数组?

更新 #1:我的代码

请求

class TestRequest extends FormRequest
{
    public function rules()
    {
        return [
            'array_field' => ['present', 'array'],
        ];
    }
}

测试


    public function testTest()
    {
        $tests = [
            [
                'value'     => null,
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error for when null is passed.',
            ],
            [
                'value'     => 'string',
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error when non empty string is passed.',
            ],
            [
                'value'     => '',
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error when empty string is passed.',
            ],
            [
                'value'     => 123,
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error when integer is passed.',
            ],
            [
                'value'     => 123.456,
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error when float is passed.',
            ],
            [
                'value'     => true,
                'outcome'  => 'failure',
                'message'   => 'Failed asserting that request returned error when boolean is passed.',
            ],
            [
                'value'     => [],
                'outcome'  => 'success',
                'message'   => 'Failed asserting that request returned no error when empty array is passed.',
            ],
            [
                'value'     => ['a', 'b'],
                'outcome'  => 'success',
                'message'   => 'Failed asserting that request returned no error when filled array is passed.',
            ],
        ];

        foreach ($tests as $test) {
            try {
                $request = new TestRequest([
                    'array_field' => $test['value']
                ]);

                $request
                    ->setContainer(app())
                    ->setRedirector(app(Redirector::class))
                    ->validateResolved();
            } catch (ValidationException $e) {
            }

            if ('failure' == $test['outcome']) {
                $this->assertTrue(
                    isset($e),
                    'Failed asserting that request throw an exception for invalid ' . json_encode($test['value']) . ' value.'
                );

                $this->assertArrayHasKey(
                    'array_field',
                    $e->errors(),
                    $test['message']
                );

                unset($e);
            } else {
                $this->assertFalse(
                    isset($e),
                    $test['message']
                );
            }
        }
    }

PhpUnit 输出

更新#2:使用的规则组合

我已经测试过

  • present + array
  • array
  • required + array

但这些都没有通过验证。

更新#3:结束

发现 this old question 描述了我的相同情况:使用可用的验证规则似乎无法实现我的目标; this comment 表示更接近的解决方案是使用 ConvertEmptyStringsToNull 将空字符串转换为空值并仅针对 null 值测试验证。

【问题讨论】:

  • 请同时发布您的代码以便更好地理解。
  • 测试代码很长,我会尽快发布一个较短的版本,但本质上它会迭代一组输入值和预期结果,所以我强烈怀疑我的问题与我的测试中有一个逻辑错误,因为对于所有其他值,它测试的行为都是正确的。

标签: arrays laravel validation laravel-7 validationrules


【解决方案1】:

好的,很多事情要改变。 (不要认为这是攻击,只是建设性的回复)

首先,您没有正确测试。请记住,测试必须只测试一件事,在这里您要测试多个(对很多不同的值没有问题),但是您要断言它是否通过,如果失败,那就是问题所在.

您必须使用@dataProvider@testWith 使用不同的值进行多个测试。

所以你的测试应该是这样的:

/**
 * @dataProvider inputValues
 */
public function testTest($value)
{
    $response = $this->post('/exampleUrl', ['array_field' => $value]);

    $response->assertSessionHasErrors('array_field');
}

public function inputValues()
{
    return [
        'null is passed' => [null],
        'string is passed' => ['string'],
        'empty string is passed' => [''],
        'integer is passed' => [123],
        'float is passed' => [123.456],
        'boolean is passed' => [true]
    ];
}

这样你会得到如下错误:

phpunit DataTest
PHPUnit 5.7.0 by Sebastian Bergmann and contributors.

...F

Time: 0 seconds, Memory: 5.75Mb

There was 1 failure:

1) DataTest::testTest with data set "empty string is passed" ('')
Session missing error: array_field.

/home/sb/DataTest.php:9

FAILURES!
Tests: 4, Assertions: 4, Failures: 1.

如您所见,我不是在测试“成功”的东西,因为它们是单独的测试。在您断言它是否正常工作的测试中,您已经传递了一个被接受的值,因此您不必测试它是否对空数组或包含数据的数组没有错误,它在该测试中是明确的。

请添加有关您正在测试的内容的更多信息,因为您的 TestRequest 非常奇怪,您不需要它以及您对其进行的所有进一步设置来测试它。


所以,为了解决您的问题,您的规则不正确。正如documentation 所说:“验证中的字段必须存在于输入数据中但可以为空。”。如果您看到source code,您将看到它可以有一个空值,例如null''。所以你想使用规则array,就是这样。它必须存在,但它必须是一个数组,它是否为空都没有关系。你想要那个!

【讨论】:

  • 这无助于回答我的问题,它没有解释为什么 presentarray 规则没有达到预期的效果,也没有给我一套解决我的问题的规则。
  • 此外,使用此代码,我不会单独测试路由、请求和控制器,因此其中任何一个的更改都可能对其他人产生不需要/意​​外的结果,并且此测试不会告诉我问题出在哪里
  • 抱歉,我添加了您的修复程序。对不起!
  • 如果我看到TestRequest 我假设您已经创建了Request 类来测试一个简单的请求,也许您正在向API 请求一些东西。尽管如此,看到 ->setContainer->setRedirector->validateResolved() 还是非常奇怪,如果我看到我会假设您正在测试框架,那是另一个 no-no 进行测试。
  • 抱歉,即使只有 array 规则,验证也会失败
猜你喜欢
  • 2016-07-31
  • 2020-09-11
  • 2018-01-03
  • 1970-01-01
  • 2019-04-27
  • 2020-05-23
  • 2020-11-12
  • 2015-08-17
  • 2019-10-21
相关资源
最近更新 更多