dani94's avatar

Unit testing ValidationRule

Hi guys!

I would like to unit test a ValidationRule, but im not really sure how to instance and test the Closure.

<?php
 
namespace App\Rules;
 
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
 
class Uppercase implements ValidationRule
{
    /**
     * Run the validation rule.
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail('The :attribute must be uppercase.');
        }
    }
}

My test

public function test ()
{
	$fail = null; // I dont know how to create this Closure
	$validator = new Uppercase();

	$validator->validate('myparam', 'myvalue', $fail);

	// i need to assert here, $fail contains the failure message
}
0 likes
3 replies
aleahy's avatar

I use the Validator::make method to do it all for me:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make(['myparam' => 'myvalue'], ['myparam' => Uppercase::class]);

$this->assertFalse($validator->passes());

You can get the message bag from the validator using $validator->messages() if you want to assert the actual message returned, but I don't tend to do that unless I'm asserting against a language file string. It would make the test brittle if someone wanted to change the wording of an error message.

2 likes
tykus's avatar

You could try this approach; setting your own Closure where the assertion is being made.

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class UppercaseValidationRuleTest extends TestCase
{
    /**
     * A basic unit test example.
     */
    public function test_example(): void
    {
        $fail = fn($message) => $this->assertEquals($message, 'The :attribute must be uppercase.');

        $validator = new \App\Rules\UppercaseOnly();

        $validator->validate('myparam', 'myvalue', $fail);
    }
}

But I don't know what this really proves...

2 likes

Please or to participate in this conversation.