<?php
namespace Tabl\VenueBundle\Tests\Form;
use Symfony\Component\Form\Test\TypeTestCase;
use Tabl\VenueBundle\Entity\Venue;
use Tabl\VenueBundle\Form\VenueType;
class VenueTypeTest extends TypeTestCase
{
public function testSubmitValidData() {
$formData = array(
'title' => 'Hello World',
);
$type = new VenueType();
$form = $this->factory->create($type);
$object = new Venue();
$object->setTitle('Hello World');
// 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);
}
}
}
我不断收到此错误消息:
Symfony\Component\Form\Exception\InvalidArgumentException: Could not load type "places_autocomplete"
如何解决这个问题?如何加载此类型以便我可以在表单上执行功能测试?
places_autocomplete
是Ivory GMaps Bundle的一部分。
VenueType.php:
namespace Acme\VenueBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Acme\VenueBundle\Entity\Attribute;
use Acme\VenueBundle\Form\AttributeType;
class VenueType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('address', 'places_autocomplete' , ['attr' => ['placeholder' => 'Start typing for suggestions'], 'label'=>'Location'])
->add('attributes', 'entity', array(
'multiple' => true,
'expanded' => true,
'property' => 'icon',
'class' => 'AcmeVenueBundle:Attribute',
))
->add('finish', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\VenueBundle\Entity\Venue'
));
}
public function getName()
{
return 'venue';
}
}
答案 0 :(得分:10)
您必须实现构建表单中使用的两种模拟表单类型的getExtensions
方法:PlacesAutocompleteType
和EntityType
这个解决方案对我有用:
<?php
namespace Acme\DemoBundle\Tests\Form;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping\ClassMetadata;
use Ivory\GoogleMapBundle\Form\Type\PlacesAutocompleteType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
use Acme\DemoBundle\Entity\Venue;
use Acme\DemoBundle\Form\VenueType;
class VenueTypeTest extends TypeTestCase
{
public function testSubmitValidData() {
$formData = array(
'title' => 'Hello World',
);
$type = new VenueType();
$form = $this->factory->create($type);
$object = new Venue();
$object->setTitle('Hello World');
// 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);
}
}
protected function getExtensions()
{
// Mock the FormType: places_autocomplete
// See Ivory\GoogleMapBundle\Tests\Form\Type\PlacesAutocompleteTypeTest
$placesAutocompleteHelperMock = $this->getMockBuilder('Ivory\GoogleMap\Helper\Places\AutocompleteHelper')
->disableOriginalConstructor()
->getMock();
$requestMock = $this->getMock('Symfony\Component\HttpFoundation\Request');
$requestMock
->expects($this->any())
->method('getLocale')
->will($this->returnValue('en'));
$placesAutocompleteType = new PlacesAutocompleteType(
$placesAutocompleteHelperMock,
$requestMock
);
// Mock the FormType: entity
$mockEntityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->getMock();
$mockRegistry->expects($this->any())->method('getManagerForClass')
->will($this->returnValue($mockEntityManager));
$mockEntityManager ->expects($this->any())->method('getClassMetadata')
->withAnyParameters()
->will($this->returnValue(new ClassMetadata('entity')));
$repo = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$mockEntityManager ->expects($this->any())->method('getRepository')
->withAnyParameters()
->will($this->returnValue($repo));
$repo->expects($this->any())->method('findAll')
->withAnyParameters()
->will($this->returnValue(new ArrayCollection()));
$entityType = new EntityType($mockRegistry);
return array(new PreloadedExtension(array(
'places_autocomplete' => $placesAutocompleteType,
'entity' => $entityType,
), array()));
}
}
希望这有帮助。 让我知道。
答案 1 :(得分:6)
这是@ Matteo的解决方案的补充,以防其他任何人遇到模拟EntityType依赖关系的相同复杂情况。这使QueryBuilder具有默认调用的select()和from()方法,这反映了在功能性内核加载上发生的事情并且在测试运行时丢失(解析器返回“SELECT WHERE ...
”)。请注意,实体字段配置数组中的类值必须用手写出,例如'class' => 'AcmeBundle\Entity\MyClass'
,而不是仅仅为了模拟存储库的简写'class' => 'AcmeBundle:MyClass'
。
...
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Validator\ConstraintViolationList;
class MyTypeCase extends TypeTestCase
{
...
protected function getExtensions()
{
// mock entity manager
$entityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->setMethods(array('getClassMetadata', 'getRepository'))
->getMock()
;
// this method will be mocked specific to the class name when provided
// by the mocked repository below - this can be generic here
$entityManager->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue(new ClassMetadata('entity')))
;
$parent = $this;
$entityManager->expects($this->any())
->method('getRepository')
->will($this->returnCallback(function($entityName) use ($parent) {
// if ever the Doctrine\ORM\Query\Parser is engaged, it will check for
// the existence of the fields used in the DQL using the class metadata
$classMetadata = new ClassMetadata($entityName);
if (preg_match('/[^a-z]MyClass$/i', $entityName)) {
$classMetadata->addInheritedFieldMapping(array('fieldName' => 'someField', 'columnName' => 'some_field'));
$classMetadata->addInheritedFieldMapping(array('fieldName' => 'anotherField', 'columnName' => 'another_field'));
}
// mock statement
$statement = $parent->getMockBuilder('\Doctrine\DBAL\Statement')
->disableOriginalConstructor()
->getMock()
;
// mock connection
$connection = $parent->getMockBuilder('\Doctrine\DBAL\Connection')
->disableOriginalConstructor()
->setMethods(array('connect', 'executeQuery', 'getDatabasePlatform', 'getSQLLogger', 'quote'))
->getMock()
;
$connection->expects($parent->any())
->method('connect')
->will($parent->returnValue(true))
;
$connection->expects($parent->any())
->method('executeQuery')
->will($parent->returnValue($statement))
;
$connection->expects($parent->any())
->method('getDatabasePlatform')
->will($parent->returnValue(new PostgreSqlPlatform()))
;
$connection->expects($parent->any())
->method('quote')
->will($parent->returnValue(''))
;
// mock unit of work
$unitOfWork = $parent->getMockBuilder('\Doctrine\ORM\UnitOfWork')
->disableOriginalConstructor()
->getMock()
;
// mock entity manager
$entityManager = $parent->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->setMethods(array('getClassMetadata', 'getConfiguration', 'getConnection', 'getUnitOfWork'))
->getMock()
;
$entityManager->expects($parent->any())
->method('getClassMetadata')
->will($parent->returnValue($classMetadata))
;
$entityManager->expects($parent->any())
->method('getConfiguration')
->will($parent->returnValue(new Configuration()))
;
$entityManager->expects($parent->any())
->method('getConnection')
->will($parent->returnValue($connection))
;
$entityManager->expects($parent->any())
->method('getUnitOfWork')
->will($parent->returnValue($unitOfWork))
;
// mock repository
$repo = $parent->getMockBuilder('\Doctrine\ORM\EntityRepository')
->setConstructorArgs(array($entityManager, $classMetadata))
->setMethods(array('createQueryBuilder'))
->getMock()
;
$repo->expects($parent->any())
->method('createQueryBuilder')
->will($parent->returnCallback(function($alias) use ($entityManager, $entityName) {
$queryBuilder = new QueryBuilder($entityManager);
$queryBuilder->select($alias)
->from($entityName, $alias)
;
return $queryBuilder;
}))
;
return $repo;
}))
;
// mock registry
$registry = $this->getMockBuilder('\Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->setMethods(array('getManagerForClass'))
->getMock()
;
$registry->expects($this->any())
->method('getManagerForClass')
->will($this->returnValue($entityManager))
;
// build the extensions
$extensions = new PreloadedExtension(
array(
'entity' => new EntityType($registry),
),
array()
);
return array($extensions);
}
}
答案 2 :(得分:1)
这是@ Matteo的解决方案的补充 - 当您使用Mockery时,您可以获得EntityType:
$mockEntityManager = \Mockery::mock('\Doctrine\ORM\EntityManager');
$mockRegistry = \Mockery::mock('Doctrine\Bundle\DoctrineBundle\Registry');
$mockRegistry->shouldReceive('getManagerForClass')->andReturn($mockEntityManager);
$mockEntityManager->shouldReceive('getClassMetadata')->andReturn(new ClassMetadata('entity'));
$repo = \Mockery::mock('Doctrine\ORM\EntityRepository');
$mockEntityManager->shouldReceive('getRepository')->andReturn($repo);
$repo->shouldReceive('findAll')->andReturn(new ArrayCollection());
$entityType = new EntityType($mockRegistry);