Symfony2:测试实体验证约束

Kas*_*een 49 symfony

有没有人有一个很好的方法来对Symfony2中的实体验证约束进行单元测试?

理想情况下,我希望能够在单元测试中访问依赖注入容器,这样我就可以访问验证器服务.一旦我有验证器服务,我就可以手动运行它:

$errors = $validator->validate($entity);
Run Code Online (Sandbox Code Playgroud)

我可以扩展WebTestCase然后client根据文档创建一个到达容器然而它感觉不对.该WebTestCaseclient在文档读取为更多的设备来测试的行为作为一个整体,因此感觉破碎用它来单元测试的实体.

那么,有没有人知道如何a)获取容器或b)在单元测试中创建验证器?

Kas*_*een 63

好吧,因为这得到两票我猜其他人都感兴趣.

我决定拿出我的铲子并且惊喜(到目前为止,无论如何),这根本不是很困难.

我记得每个Symfony2组件都可以在独立模式下使用,因此我可以自己创建验证器.

查看文档:https://github.com/symfony/Validator/blob/master/ValidatorFactory.php

我意识到,由于有一个ValidatorFactory,创建一个验证器是微不足道的(特别是我通过注释完成的验证,虽然如果你查看我上面链接的页面上的docblock,你也会找到验证xml和yml的方法).

第一:

# Symfony >=2.1
use Symfony\Component\Validator\Validation;
# Symfony <2.1
use Symfony\Component\Validator\ValidatorFactory;
Run Code Online (Sandbox Code Playgroud)

然后:

# Symfony >=2.1
$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
# Symfony <2.1
$validator = ValidatorFactory::buildDefault()->getValidator();

$errors = $validator->validate($entity);

$this->assertEquals(0, count($errors));
Run Code Online (Sandbox Code Playgroud)

我希望这有助于其他任何良心不允许他们使用WebTestCase的人;).

  • 在Symfony 2.1中不推荐使用ValidatorFactory.如果使用注释,可以使用Validation :: createValidatorBuilder() - > enableAnnotationMapping() - > getValidator()替换它. (28认同)

Mat*_*att 38

我们最终会推出自己的基本测试用例,以便从测试用例中访问依赖容器.这里的课程有问题:

<?php

namespace Application\AcmeBundle\Tests;

// This assumes that this class file is located at:
// src/Application/AcmeBundle/Tests/ContainerAwareUnitTestCase.php
// with Symfony 2.0 Standard Edition layout. You may need to change it
// to fit your own file system mapping.
require_once __DIR__.'/../../../../app/AppKernel.php';

class ContainerAwareUnitTestCase extends \PHPUnit_Framework_TestCase
{
    protected static $kernel;
    protected static $container;

    public static function setUpBeforeClass()
    {
        self::$kernel = new \AppKernel('dev', true);
        self::$kernel->boot();

        self::$container = self::$kernel->getContainer();
    }

    public function get($serviceId)
    {
        return self::$kernel->getContainer()->get($serviceId);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此基类,您现在可以在测试方法中执行此操作以访问验证器服务:

$validator = $this->get('validator');
Run Code Online (Sandbox Code Playgroud)

我们决定使用静态函数而不是类构造函数,但是您可以轻松地更改行为以将内核直接实例化到构造函数中,而不是依赖于setUpBeforeClassPHPUnit提供的静态方法.

另外,请记住,测试用例中的每个单独测试方法都不会彼此隔离,因为容器是针对整个测试用例共享的.对容器进行修改可能会对您的其他测试方法产生影响,但如果您只访问该validator服务则不应该这样.但是,通过这种方式,测试用例将运行得更快,因为您不需要为每个测试方法实例化和引导新内核.

为了便于参考,我们从这篇博文中找到了本课程的灵感.它是用法语写的,但我更愿意归功于它属于谁:)

问候,
马特

  • 请注意,引导整个内核可能很重,可能会大大减慢您的测试速度.谨慎使用. (3认同)

And*_*mko 27

我喜欢Kasheens的答案,但它不再适用于Symfony 2.3.几乎没有变化:

use Symfony\Component\Validator\Validation;
Run Code Online (Sandbox Code Playgroud)

$validator = Validation::createValidatorBuilder()->getValidator();
Run Code Online (Sandbox Code Playgroud)

如果要验证Annotations,请使用如下所示的enableAnnotationMapping():

$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
Run Code Online (Sandbox Code Playgroud)

其余的保持不变:

$errors = $validator->validate($entity);
$this->assertEquals(0, count($errors));
Run Code Online (Sandbox Code Playgroud)

  • 我真的不知道为什么Symfony Forms的官方单元测试文档中没有显示这一点!感谢您指出这个解决方案. (2认同)

Cha*_*ste 5

使用Symfony 2.8,您现在可以通过AbstractConstraintValidatorTest以下方式使用该类:

<?php
namespace AppBundle\Tests\Constraints;

use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest;
use AppBundle\Constraints\MyConstraint;
use AppBundle\Constraints\MyConstraintValidator;
use AppBundle\Entity\MyEntity;
use Symfony\Component\Validator\Validation;

class MyConstraintValidatorTest extends AbstractConstraintValidatorTest
{
    protected function getApiVersion()
    {
        return Validation::API_VERSION_2_5;
    }

    protected function createValidator()
    {
        return new MyConstraintValidator();
    }

    public function testIsValid()
    {
        $this->validator->validate(null, new MyEntity());

        $this->assertNoViolation();
    }

    public function testNotValid()
    {
        $this->assertViolationRaised(new MyEntity(), MyConstraint::SOME_ERROR_NAME);
    }
}
Run Code Online (Sandbox Code Playgroud)

你有一个很好的样本与IpValidatorTest类


小智 5

对于 Symfony 4, /sf/answers/2931926301/中的答案必须稍作更改:

使用ConstraintValidatorTestCase而不是AbstractConstraintValidatorTest.