对自定义 symfony 约束进行单元测试

REB*_*LUE 7 php unit-testing symfony mockery

这应该非常简单,但今天下午它让我发疯,对自定义 symfony 验证器进行单元测试的正确方法是什么?我能找到的所有文章都与我的做法完全相同

class Foo extends Constraint
{
    public string $message = 'The string "{{ string }}" is not a valid foo.';
}
Run Code Online (Sandbox Code Playgroud)
class FooValidator extends ConstraintValidator
{
    /**
     * {@inheritdoc}
     */
    public function validate($value, Constraint $constraint): void
    {
        if ($value !== 'foo') {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ string }}', $value)
                ->addViolation();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该有效,而且确实有效,但是它会导致 9 个弃用警告


  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".
Run Code Online (Sandbox Code Playgroud)

由于@internal这些方法上的注释。因此,如果您将SymfonyTestsListener弃用设置为 0,则会导致测试失败。

有谁知道如何在不被弃用的情况下测试它?我一直在兜圈子。我只尝试了部分模拟ExecutionContextInterface和直接模拟ExecutionContext,这没有什么区别(后者也标记为@internal)。

我确信有一个非常简单的解决方案,但我一直在兜圈子,我在搜索时发现的所有内容基本上都是使用 PHPUnit 的 createMock 做同样的事情(按照这个速度我可能会这样做......)

REB*_*LUE 11

看来你可以用这个作为例子https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Validator/Tests/Constraints/BlankValidatorTest.php它扩展了 ConstraintValidatorTestCase... 诚然,这只是对某些事情使用 PHPUnit 模拟,对其他事情使用具体类,但我想这就是实现它的方法