0

I use Symfony3 and forms. I have a formType and I want to test it. I follow this article : http://symfony.com/doc/current/form/unit_testing.html

My formType is the following :

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Required;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $aOption)
    {

        $builder->add('name', TextType::class, array(
            'constraints' => array(
                new NotBlank(),
                new Length(array('min' => 3)),
            ),
        ))
            ->add('age', IntegerType::class, array(
                'constraints' => array(
                    new GreaterThanOrEqual(array('value' => 18)),
                    new Required()),

            ));
    }
}

The name must have more than 3 chars and the age must be greater than 18. I want to test with phpunit, with invalid data to submit. The age I submut is invalid because it is less than 18, and the name is invalid because it contains 1 char. My test class is the following :

namespace Tests\AppBundle\Controller;

use AppBundle\Form\UserType;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Form;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Validator\ValidatorInterface;

class UserTypeTest extends TypeTestCase
{
    private $validator;
    protected function getExtensions()
    {
        $this->validator = $this->createMock(ValidatorInterface::class);
        // use getMock() on PHPUnit 5.3 or below
        // $this->validator = $this->getMock(ValidatorInterface::class);
        $this->validator
            ->method('validate')
            ->will($this->returnValue(new ConstraintViolationList()));
        $this->validator
            ->method('getMetadataFor')
            ->will($this->returnValue(new ClassMetadata(Form::class)));
        return array(
            new ValidatorExtension($this->validator),
        );
    }
    public function testIndex()
    {
        $formData = array(
            'name' => 'a',
            'age'  => '4'
        );
        $formBuilder = $this->factory->createBuilder(UserType::class);
        $form = $formBuilder->getForm();
        $form->submit($formData);
        $this->assertTrue($form->isSynchronized());
        $this->assertFalse($form->isValid());

    }
}

When I want to run the tests with invalid data to submit, I have failure :

./vendor/bin/phpunit tests/AppBundle/Controller/UserTypeTest.php  
Failed asserting that true is false.

Why the form is always valid ?

1 Answer 1

1

Your form is always valid because your new ConstraintViolationList() is empty.

I can suggest you to replace your UserTypeTest::getExtensions() method by the following :

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;
}


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);
}

With this ValidatorExtension, you should have not empty ConstraintViolationList

Sign up to request clarification or add additional context in comments.

2 Comments

Thx. I have an error : TypeError: Argument 1 passed to Tests\AppBundle\Controller\UserTypeTest::createValidator() must be an instance of Tests\AppBundle\Controller\MetadataFactoryInterface, instance of Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory given
Provided solution doesn't work, there is no such class FakeMetadataFactory

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.