Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 使用实体对Symfony表单进行单元测试_Php_Forms_Unit Testing_Symfony - Fatal编程技术网

Php 使用实体对Symfony表单进行单元测试

Php 使用实体对Symfony表单进行单元测试,php,forms,unit-testing,symfony,Php,Forms,Unit Testing,Symfony,我很难对内部有“实体”字段的Symfony表单进行单元测试 我找到了潜在的解决方案,但我无法让它们发挥作用 这是我的密码: FormsTest.php protected function setUp() { parent::setUp(); $this->factory = Forms::createFormFactoryBuilder() ->addExtensions($this->getExtensions()) -&g

我很难对内部有“实体”字段的Symfony表单进行单元测试

我找到了潜在的解决方案,但我无法让它们发挥作用

这是我的密码:

FormsTest.php

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

    $this->factory = Forms::createFormFactoryBuilder()
        ->addExtensions($this->getExtensions())
        ->getFormFactory();
}

protected function getExtensions()
{
    $mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
        ->disableOriginalConstructor()
        ->getMock();

    $mockEntityType->expects($this->any())->method('getName')
        ->will($this->returnValue('entity'));

    return array(new PreloadedExtension(array(
        $mockEntityType->getName() => $mockEntityType,
    ), array()));
}

public function testSubmitValidData()
{
    $formData = array(
        'name' => 'Mbalmayo',
        'latitude' => 3.5165475,
        'longitude' => 11.5144015,
        'zoomLevel' => 12.0,
        'region' => 'Centre',
    );

    $type = new CitiesType();
    $form = $this->factory->create($type, null);

    $object = new Cities();
    $object->fromArray($formData);

    // submit the data to the form directly
    $form->submit($formData);

    $this->assertTrue($form->isSynchronized());
    $this->assertEquals($object, $form->getData());

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

    foreach (array_keys($formData) as $key) {
        $this->assertArrayHasKey($key, $children);
    }
}
/**
 * Builds the form data for the cities
 *
 * @param FormBuilderInterface  $builder The FormBuilderInterface to use
 * @param array                 $options The options for the form, if any
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        /* Several adds that are pointless for this problem */
        ->add('region', 'entity', array('class' => 'SmopaAgentFinderBundle:Regions',
                'property' => 'name',
                'required' => true,
                'label' => 'city.new.region',
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('r')
                        ->orderBy('r.name', 'ASC');
                },
                'empty_value' => 'Select city\'s region',
                'attr' => array('class' => 'new_city_combo_box')
            )
        );
}
此代码基于我以前找到的解决方案

CitiesType.php

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

    $this->factory = Forms::createFormFactoryBuilder()
        ->addExtensions($this->getExtensions())
        ->getFormFactory();
}

protected function getExtensions()
{
    $mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
        ->disableOriginalConstructor()
        ->getMock();

    $mockEntityType->expects($this->any())->method('getName')
        ->will($this->returnValue('entity'));

    return array(new PreloadedExtension(array(
        $mockEntityType->getName() => $mockEntityType,
    ), array()));
}

public function testSubmitValidData()
{
    $formData = array(
        'name' => 'Mbalmayo',
        'latitude' => 3.5165475,
        'longitude' => 11.5144015,
        'zoomLevel' => 12.0,
        'region' => 'Centre',
    );

    $type = new CitiesType();
    $form = $this->factory->create($type, null);

    $object = new Cities();
    $object->fromArray($formData);

    // submit the data to the form directly
    $form->submit($formData);

    $this->assertTrue($form->isSynchronized());
    $this->assertEquals($object, $form->getData());

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

    foreach (array_keys($formData) as $key) {
        $this->assertArrayHasKey($key, $children);
    }
}
/**
 * Builds the form data for the cities
 *
 * @param FormBuilderInterface  $builder The FormBuilderInterface to use
 * @param array                 $options The options for the form, if any
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        /* Several adds that are pointless for this problem */
        ->add('region', 'entity', array('class' => 'SmopaAgentFinderBundle:Regions',
                'property' => 'name',
                'required' => true,
                'label' => 'city.new.region',
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('r')
                        ->orderBy('r.name', 'ASC');
                },
                'empty_value' => 'Select city\'s region',
                'attr' => array('class' => 'new_city_combo_box')
            )
        );
}
目前,我遇到了以下错误:

1) FormsTest::testSubmitValidData Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: 选项“属性”、“类”、“空值”、“标签”、“属性”, “查询生成器”、“必需”不存在。已知选项为:“”


我需要用测试覆盖这些表单,我完全没有想法。有任何帮助吗?

从symfony 2.7开始,“属性”选项已被“选择标签”取代


发生这种情况是因为选项解析器不知道这些选项。EntityType模拟应声明它们:

对于Symfony 2.7:

//使用Symfony\Component\OptionsResolver\OptionsResolver;
$mockEntityType->method('setDefaultOptions')->将(
$this->returnCallback(
功能(选项解析器$resolver)
{
$resolver->setDefaults(
排列(
“选择标签”=>null,
'class'=>null,
“查询生成器”=>null,
“必需”=>null,
)
);
}
)
);

我想介绍一下我的解决方案。首先,我将实体类型注入到表单中。以下是我在UserBundle中所做的操作,它扩展了FOSUserBundle,因为我需要将组分配给用户:

namespace UserBundle\Form\Type;


use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use UserBundle\Entity\Group;

/**
 * Class UserType
 * @package UserBundle\Form\Type
 */
class UserType extends AbstractType
{

    /**
     * @var array
     */
    private $roles;

    /**
     * GroupType constructor.
     * @param $roles
     */
    public function __construct($roles)
    {
        $this->roles = $roles;
    }

    /**
     * @var EntityType
     */
    private $entityType;

    /**
     * @param EntityType $entityType
     * @internal param $imagepath
     */
    public function setEntityType(
        $entityType
    )
    {
        $this->entityType = $entityType;
    }

    /**
     * Mainly for testing
     * @return bool
     */
    public function hasEntityType(){
        return $this->entityType instanceof EntityType;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->add('enabled',
                CheckboxType::class,
                [
                    'label' => 'smartadmin.user.active',
                    'required' => false
                ]
            )->add('groups',
                $this->entityType,
                [
                    'class' => Group::class,
                    'property' => 'name',
                    'multiple' => true,
                    'expanded' => true,
                    'required' => false,
                    'label' => 'smartadmin.user.groups'
                ]
            )->add('username',
                TextType::class,
                [
                    'label' => 'form.username',
                    'translation_domain' => 'FOSUserBundle'
                ]
            )->add('email',
                EmailType::class,
                [
                    'label' => 'form.email',
                    'translation_domain' => 'FOSUserBundle',
                    'constraints' => [new Email()]
                ]
            )->add('firstname',
                TextType::class,
                [
                    'label' => 'smartadmin.user.firstname'
                ]
            )->add('lastname',
                TextType::class,
                [
                    'label' => 'smartadmin.user.lastname'
                ]
            )->add('gender',
                ChoiceType::class,
                [
                    'label' => 'smartadmin.user.gender',
                    'choices' => [1 => 'smartadmin.user.gender_male', 2 => 'smartadmin.user.gender_female']
                ]

            )->add('plainPassword', RepeatedType::class,
                [
                    'type' => PasswordType::class,
                    'options' => array('translation_domain' => 'FOSUserBundle'),
                    'first_options' => array('label' => 'form.new_password'),
                    'second_options' => array('label' => 'form.new_password_confirmation'),
                    'invalid_message' => 'fos_user.password.mismatch',
                    'required' => false
                ]
            );
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'UserBundle\Entity\User',
            'csrf_token_id' => 'profile'
        ));
    }
}
在我的控制器中:

$oUser = $this->userRepository->find($userId);

$userType = new UserType($this->roleService->getAvailableRoles());
$userType->setEntityType(new EntityType($this->doctrine));
$oForm = $this->formFactory->createBuilder($userType)
    ->setData($oUser)
    ->getForm();
为了测试此表单,我创建了一个替换实体类型,该类型仅提供与entityType类似的必需方法:

namespace UserBundle\Tests\Form\Type;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Util\StringUtil;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

/**
 * Class EntityTypeSimulator
 * @package UserBundle\Tests\Form\Type
 */
class EntityTypeSimulator extends AbstractType
{

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    }

    /**
     * {@inheritdoc}
     */
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
    }

    /**
     * {@inheritdoc}
     */
    public function finishView(FormView $view, FormInterface $form, array $options)
    {
    }

    /**
     * {@inheritdoc}
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        if (!$resolver instanceof OptionsResolver) {
            throw new \InvalidArgumentException(sprintf('Custom resolver "%s" must extend "Symfony\Component\OptionsResolver\OptionsResolver".', get_class($resolver)));
        }

        $this->configureOptions($resolver);
    }

    /**
     * Configures the options for this type.
     *
     * @param OptionsResolver $resolver The resolver for the options.
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'multiple' => false,
            'expanded' => false,
            'class' => null,
            'property' => true,
            'invalid_message' => null
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        // As of Symfony 2.8, the name defaults to the fully-qualified class name
        return get_class($this);
    }

    /**
     * Returns the prefix of the template block name for this type.
     *
     * The block prefixes default to the underscored short class name with
     * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile").
     *
     * @return string The prefix of the template block name
     */
    public function getBlockPrefix()
    {
        $fqcn = get_class($this);
        $name = $this->getName();

        // For BC: Use the name as block prefix if one is set
        return $name !== $fqcn ? $name : StringUtil::fqcnToBlockPrefix($fqcn);
    }

    /**
     * {@inheritdoc}
     */
    public function getParent()
    {
        return 'Symfony\Component\Form\Extension\Core\Type\FormType';
    }
}
现在是我的测试用例:

namespace UserBundle\Tests\Form\Type;


use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Validator\Validation;
use UserBundle\Entity\User;
use UserBundle\Form\Type\UserType;

/**
 * Class UserTypeTest
 * @package UserBundle\Tests\Form\Type
 */
class UserTypeTest extends TypeTestCase
{

    /**
     * Load the ValidatorExtension so RepeatedType can resolve 'invalid_message'
     * @return array
     */
    protected function getExtensions()
    {
        return array(new ValidatorExtension(Validation::createValidator()));
    }

   public function testGroupType(){
        $formData['user'] = [
            'enabled' => 1,
            'groups' => [1,2,3],
            'username' => 'Test username',
            'email' => 'test@email.de',
            'firstname' => 'Test Firstname',
            'lastname' => 'Test Lastname',
            'gender' => 1,
            'plainPassword' => ['first' => 'Test Password', 'second' => 'Test Password']
        ];

        $roles = ['ROLE_USER'];
        $entity = new User('Test name');

        $type = new UserType($roles);
        $type->setEntityType(new EntityTypeSimulator());
        $oFormBuilder = $this->factory->createBuilder();

        $oFormBuilder->add('user', $type);
        $oFormBuilder->setData(['user' => $entity]);

        $oForm = $oFormBuilder->getForm();
        $oForm->submit($formData);
        $oForm->handleRequest();

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

        $view = $oForm->createView();
        $children = $view->children['user']->children;

        foreach (array_keys($formData['user']) as $key) {
            $this->assertArrayHasKey($key, $children);
        }
        $this->assertEquals($formData['user']['username'], $entity->getUsername());
        $this->assertEquals($formData['user']['email'], $entity->getEmail());
    }

}

错误来自表单声明,而不是您的测试。请参阅,选项
attr
空值
等不适用于此类字段。但是
class
可用,因此这可能不是原因。请查看此问题:。我认为EntityType应该是开箱即用的可测试的。通过此设置,我得到了一个TypeError:参数1传递给Symfony\Bridge\Doctrine\Form\Type\DoctrineType::\uu construct()必须实现接口原则\Common\Persistence\manager注册表,未给出,使用symfony 3.0.6在第85行调用/var/www/shn/vendor/symfony/symfony/src/symfony/Component/Form/FormRegistry.php。当然,我将setDefaultOptions更改为configureOptions