Testez unitairement un validateur personnalisé Symfony

Publié le 05/11/2022 • Actualisé le 05/11/2022


English language detected! 🇬🇧

  We noticed that your browser is using English. Do you want to read this post in this language?

Read the english version 🇬🇧 Close

Dans ce bout de code, nous voyons comment tester unitairement un validateur personnalisé Symfony. On apprend tous les jours : j'ai fait ce snippet inspiré par diverses ressources sur le web, puis j'ai relu la documentation, et j'ai réalisé qu'il existait désormais un cas de test ConstraintValidatorTestCase que je connaissais pas et que je n'avais jamais utilisé. Ce bout de code est toujours utile, au moins nous voyons comment utiliser des mocks. Dans le prochain snippet, nous verrons comme faire pareil avec le cas de test ConstraintValidatorTestCase. La contrainte que j'utilise ici est factice, elle teste juste qu'une chaîne de caractères n'est pas égale à la valeur "coil". Avec ces tests unitaires, on obtient 100% de couverture de code sur notre contrainte personnalisée.


<?php

declare(strict_types=1);

namespace App\Tests\Unit\Validator;

use App\Entity\Article;
use App\Validator\NotCoil;
use App\Validator\NotCoilValidator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Context\ExecutionContext;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilder;

final class NotCoilTest extends TestCase
{
    /**
     * You can put this method in a trait.
     */
    private function initValidator(ConstraintValidator $validator, ?string $expectedMessage = null): void
    {
        $builder = $this->getMockBuilder(ConstraintViolationBuilder::class)
            ->disableOriginalConstructor()
            ->getMock();

        $context = $this->getMockBuilder(ExecutionContext::class)
            ->disableOriginalConstructor()
            ->getMock();

        if ($expectedMessage === null) {
            // no violation expected
            $context->expects(self::never())->method('buildViolation');
        } else {
            // a violation is expected
            $builder->expects(self::once())->method('addViolation');
            $context->expects(self::once())
                ->method('buildViolation')
                ->with(self::equalTo($expectedMessage))
                ->willReturn($builder);
        }

        /* @var ExecutionContext $context */
        $validator->initialize($context);
    }

    /**
     * Nominal cases, no validation error.
     */
    public function testNotCoilValidatorSuccess(): void
    {
        $constraint = new NotCoil();
        $validator = new NotCoilValidator();
        $this->initValidator($validator);
        $validator->validate('Foobar', $constraint);
        $validator->validate('', $constraint);
    }

    /**
     * Nominal case, a violation is raised.
     */
    public function testNotCoilValidatorViolations(): void
    {
        $constraint = new NotCoil();
        $validator = new NotCoilValidator();
        $this->initValidator($validator, 'The value should not be COil');
        $validator->validate('COil', $constraint);
    }

    /**
     * Value type failure.
     */
    public function testNotCoilValidatorUnexpectedValueException(): void
    {
        $constraint = new NotCoil();
        $validator = new NotCoilValidator();
        $this->expectException(UnexpectedValueException::class);
        $validator->validate(new Article(), $constraint); // not the good value type!
    }

    /**
     * Constraint type failure.
     */
    public function testNotCoilValidatorUnexpectedTypeException(): void
    {
        $constraint = new NotCoil();
        $validator = new NotCoilValidator();
        $this->expectException(UnexpectedTypeException::class);
        $validator->validate($constraint, new Length(['max' => 5])); // not the good constraint!
    }
}

 Plus sur Stackoverflow   Lire la doc  Snippet aléatoire

  Travaillez avec moi !