7

This should be incredibly simple but it is driving me mad this afternoon, what is the correct way to unit test a custom symfony validator? All the articles I can find have exactly the same way as I am doing it

class Foo extends Constraint
{
    public string $message = 'The string "{{ string }}" is not a valid foo.';
}
class FooValidator extends ConstraintValidator
{
    /**
     * {@inheritdoc}
     */
    public function validate($value, Constraint $constraint): void
    {
        if ($value !== 'foo') {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ string }}', $value)
                ->addViolation();
        }
    }
}
class FooValidatorTest extends TestCase
{

    /** @test  */
    public function validate(): void
    {
        $this->expectNotToPerformAssertions();

        $constraint = new Foo();
        $context    = \Mockery::mock(ExecutionContextInterface::class);
        $builder    = \Mockery::mock(ConstraintViolationBuilderInterface::class);

        $context->shouldReceive('buildViolation')
            ->with($constraint->message)
            ->andReturn($this->builder);

        $builder->shouldReceive('setParameter')
            ->with('{{ string }}', 'foo-bar')
            ->andReturn($builder);

        $builder->shouldReceive('addViolation');

        $validator = new FooValidator();
        $validator->initialize($context);
        $validator->validate('foo-bar', $constraint);
    }
}

This should work, and indeed it does, however it causes like 9 deprecation warnings


  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::setGroup()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::setConstraint()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::markGroupAsValidated()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::isGroupValidated()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::markConstraintAsValidated()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::isConstraintValidated()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::markObjectAsInitialized()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

  1x: The "Symfony\Component\Validator\Context\ExecutionContextInterface::isObjectInitialized()" method is considered internal Used by the validator engine. Should not be called by user *           code. It may change without further notice. You should not extend it from "Mockery_0_Symfony_Component_Validator_Context_ExecutionContextInterface".

due to the @internal annotation on those methods. So if you are using SymfonyTestsListener with deprecations set to 0 it causes the tests to fail.

Does anyone have any idea how you are supposed to test this without getting deprecations? I have been going round in circles. I have tried only a partial mock of ExecutionContextInterface and mocked ExecutionContext directly and it makes no difference (and the latter is also marked as @internal).

I am sure there is a really simple solution but I have been going around in circles, and everything I find when searching is basically doing the same thing just with PHPUnit's createMock (which at this rate I may just do...)

REBELinBLUE
  • 193
  • 2
  • 8

1 Answers1

10

It seems that you can use this as an example https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Validator/Tests/Constraints/BlankValidatorTest.php which extends ConstraintValidatorTestCase... which admittedly just uses the PHPUnit mocks for some things and concrete classes for others, but I guess that is the way to do it

REBELinBLUE
  • 193
  • 2
  • 8