0

I'm trying to validate a required (possibly) empty array in my FormRequest.

I'm usign the present and array validation rules, since i want the value to be passed, but it coul be an empty array.

The problem is that my test fail on an empty string (i.e.: ''), telling me that my request doesn't throw an expected ValidationException with that value.

My test cover the following values for the given field:

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

How can i test that expected request parameter is present, is an array and is possibly an empty array?

Update #1: My Code

The request

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

The test


    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 output

enter image description here

Update #2: the combinations of rules used

I've tested with

  • present + array
  • array
  • required + array

but none of those make the validation pass.

Update #3: the end

Found this old question that depict my same situation: it seems impossible to achive my goal with available validation rules; this comment states that the closer solution is to use ConvertEmptyStringsToNull to convert empty strings to nulls and test validation just against the null value.

2
  • Please also post your piece of code for better understanding. Commented Apr 6, 2021 at 13:12
  • The test code is quite long, i'll post a shorter version asap, but essentially it iterate over an array of pairs of input value and expected outcome, so i strongly doubt that my problem is related to a logic error in my test, since for all the others values it test behave correctly. Commented Apr 6, 2021 at 13:15

1 Answer 1

-1

Okay, a lot of things to change. (Do not take this as an attack, just a constructive reply)

First of all, you are not testing correctly. Remember that a test must only test one thing, here you are testing more than one (no problem with a lot of different values) but you are asserting if it passes and if it fails, that is the problem.

You have to use @dataProvider or @testWith to do multiple tests with different values.

So your test would look like this:

/**
 * @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]
    ];
}

This way you will get an error like:

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.

As you can see, I am not testing "successful" things, as those are separate tests. On the tests you assert if it is working, you are already passing a value that is accepted, so you don't have to test if it has no error with an empty array or an array with data, it is explicit on that test.

Please, add more info about what you are testing, as your TestRequest is super weird, you would not require that and all the further setup you have on it to test it.


So, to solve your issue, your rules are not correct. As the documentation says: "The field under validation must be present in the input data but can be empty.". If you see the source code you will see that it can have an empty value like null or ''. So you want to use the rule array and that's it. It must be present but it has to be an array, it doesn't matter if it is empty or not. You want that !

Sign up to request clarification or add additional context in comments.

13 Comments

This is not contributing to answer my question, it doesn't explain why present and array rules are not doing what expected, nor it gives me a set of rules that solve my problem.
moreover, with this code i'm not testing routes, requests and controllers in isolation, so a change in any of those may have unwanted/unexpected results on the others, and this test will not tell me where is the arised problem
Sorry, I added your fix. Sorry for that !
If I see TestRequest I am assuming you have created your on Request class to test a simple request, maybe you are requesting something to an API. Still, it is super weird to see ->setContainer, ->setRedirector, and ->validateResolved(), that is super weird to see, if I see that I will assume you are testing the framework and that is another no-no for a test.
sorry but even with just the array rule the validation is failing
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.