简体   繁体   English

带约束的 Symfony2 单元测试表单

[英]Symfony2 Unit Testing Forms with constraints

I've got a form which isn't connected to a entity but does have constraints like mentioned in here: http://symfony.com/doc/current/book/forms.html#adding-validation我有一个未连接到实体但确实具有此处提到的约束的表单: http : //symfony.com/doc/current/book/forms.html#adding-validation

ContactBundle\\Tests\\Form\\Type\\TestedTypeTest::testSubmitValidData Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException: The option "constraints" does not exist. ContactBundle\\Tests\\Form\\Type\\TestedTypeTest::testSubmitValidData Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException:选项“约束”不存在。 Known options are: "action", "attr", "auto_initialize", "block_name", "by_reference", "compound", "data", "data_class", "disabled", "empty_data", "error_bubbling", "inherit_data", "label", "label_attr", "mapped", "max_length", "method", "pattern", "post_max_size_message", "property_path", "read_only", "required", "translation_domain", "trim", "virtual"已知选项有:“action”、“attr”、“auto_initialize”、“block_name”、“by_reference”、“compound”、“data”、“data_class”、“disabled”、“empty_data”、“error_bubbling”、“inherit_data” ", "label", "label_attr", "mapped", "max_length", "method", "pattern", "post_max_size_message", "property_path", "read_only", "required", "translation_domain", "trim", “虚拟的”

Here is part of the form:这是表格的一部分:

class ContactType extends AbstractType
{

/**
 * Build the form
 * @param \Symfony\Component\Form\FormBuilderInterface $builder BuilderInterface
 * @param array $aOption Array of options
 */
public function buildForm(FormBuilderInterface $builder, array $aOption)
{
    ///..
    $builder->add('name', 'text', array(
                'constraints' => array(
                    new NotBlank(),
                    new Length(array('min' => 3)),
                ),
            ))
            ->add('address', 'textarea', array(
                'required' => false
            ))
            //..
            ;
    //..

Here is the unit test这是单元测试

class TestedTypeTest extends TypeTestCase
{

public function testSubmitValidData()
{
    $formData = array(
        'name' => 'Test Name',
        'address' => '',
    );
    $type = new ContactType();
    $form = $this->factory->create($type, $formData);
    $form->submit($formData);

    $this->assertTrue($form->isSynchronized());

    $view = $form->createView();
    $children = $view->children;

    foreach (array_keys($formData) as $key) {
        $this->assertArrayHasKey($key, $children);
    }
}
}

I'm guessing that this is a problem with the test instead of the form as the form works as expected.我猜这是测试而不是表单的问题,因为表单按预期工作。 I'm not sure what I should change.我不确定我应该改变什么。 Any help or advice would be handy任何帮助或建议都会很方便

Thanks谢谢

I think the problem is that you also pass the formData to the factory's create method. 我认为问题在于您还将 formData 传递给工厂的 create 方法。

\n

It should be fine to just pass the form data via $form->submit($formData) like you already have in your code 通过 $form->submit($formData)传递表单数据应该 $form->submit($formData)就像你已经在你的代码中一样

More docs: http://symfony.com/doc/current/cookbook/form/unit_testing.html更多文档: http : //symfony.com/doc/current/cookbook/form/unit_testing.html

EDIT:编辑:

Well it seems you have to add the validator/constaint extensions to the factory object in your test setup like stated here http://symfony.com/doc/current/cookbook/form/unit_testing.html#adding-custom-extensions好吧,似乎您必须在测试设置中将验证器/containt 扩展添加到工厂对象,如此处所述http://symfony.com/doc/current/cookbook/form/unit_testing.html#adding-custom-extensions

Yes Rob was right I needed to add validator/constraint extensions.是的,Rob 是对的,我需要添加验证器/约束扩展。 Like so:像这样:

 class TestedTypeTest extends TypeTestCase
 {

  protected function setUp()
  {
    parent::setUp();

    $validator = $this->getMock('\Symfony\Component\Validator\Validator\ValidatorInterface');
    $validator->method('validate')->will($this->returnValue(new ConstraintViolationList()));
    $formTypeExtension = new FormTypeValidatorExtension($validator);
    $coreExtension = new CoreExtension();

    $this->factory = Forms::createFormFactoryBuilder()
            ->addExtensions($this->getExtensions())
            ->addExtension($coreExtension)
            ->addTypeExtension($formTypeExtension)
            ->getFormFactory();
}
//..

I suggest you to override the TypeTestCase::getExtensions() method我建议你覆盖 TypeTestCase::getExtensions() 方法

use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Form;
use Symfony\Component\Translation\IdentityTranslator;
use Symfony\Component\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Context\ExecutionContextFactory;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
use Symfony\Component\Validator\Validator\RecursiveValidator;

....

   public function getExtensions()
    {
        $extensions = parent::getExtensions();
        $metadataFactory = new FakeMetadataFactory();
        $metadataFactory->addMetadata(new ClassMetadata(  Form::class));
        $validator = $this->createValidator($metadataFactory);

        $extensions[] = new CoreExtension();
        $extensions[] = new ValidatorExtension($validator);

        return $extensions;
    }

add the method createValidator() in your test class :在您的测试类中添加方法 createValidator() :

    protected function createValidator(MetadataFactoryInterface $metadataFactory, array $objectInitializers = array())
    {
        $translator = new IdentityTranslator();
        $translator->setLocale('en');
        $contextFactory = new ExecutionContextFactory($translator);
        $validatorFactory = new ConstraintValidatorFactory();
        return new RecursiveValidator($contextFactory, $metadataFactory, $validatorFactory, $objectInitializers);
    }

No need to override TypeTestCase::getTypeExtensions() because ValidatorExtension class already has a loadTypeExtensions() method.不需要覆盖 TypeTestCase::getTypeExtensions() 因为 ValidatorExtension 类已经有一个 loadTypeExtensions() 方法。

Then, your test method can be like this :然后,您的测试方法可以是这样的:

public function testSubmitValidData()
{
    $formData = array(
        'name' => 'Test Name',
        'address' => '',
    );
    $form = $this->factory->create(ContactType::class);
    $form->submit($formData);
    $this->assertTrue($form->isValid());
    $this->assertTrue($form->isSynchronized());

    $view = $form->createView();
    $children = $view->children;

    foreach (array_keys($formData) as $key) {
        $this->assertArrayHasKey($key, $children);
    }
}

You can test invalid data :您可以测试无效数据:

public function testSubmitInvalidValidData()
{
    $formData = array(
        'name' => 'T',
    );
    $form = $this->factory->create(ContactType::class);
    $form->submit($formData);
    $this->assertFalse($form->isValid());
    $this->assertFalse($view->children['name']->vars['valid']);

}

sources :来源:

This problem can still occurs with Symfony 4.4 but it is easy to solve.这个问题在 Symfony 4.4 中仍然会出现,但很容易解决。

The ValidatorExtensionTrait must be added to the class that runs the test. ValidatorExtensionTrait必须添加到运行测试的类中。

use Symfony\Component\Form\Test\TypeTestCase;

class TestedTypeTest extends TypeTestCase
{
    use \Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait;

    public function testSubmitValidData()
    {
        $formData = [...];
        $type = new ContactType();
        $form = $this->factory->create($type, $formData);
    }
}

The trait takes care of adding the extension required to make the "constraints" option available.该特征负责添加使“约束”选项可用所需的扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM