Reputation:
<?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);
}
}
}
I keep getting this error message:
Symfony\Component\Form\Exception\InvalidArgumentException: Could not load type "places_autocomplete"
How can this be fixed? How do I load this type so I could perform a functional test on form?
places_autocomplete
is a part of the 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';
}
}
Upvotes: 8
Views: 4247
Reputation: 253
This is in addition to @Matteo's solution - when You use Mockery, You can get EntityType this:
$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);
Upvotes: 1
Reputation: 603
This is in addition to @Matteo's solution, in case anyone else runs into the same complications mocking the EntityType dependencies. This gets the QueryBuilder to have the select() and from() methods called by default, which mirrors what happens on a functional kernel load and was missing on the test runs (parser was returning "SELECT WHERE ...
"). Note that the class value in the entity field configuration array must be written out longhand, e.g. 'class' => 'AcmeBundle\Entity\MyClass'
, rather than the shorthand 'class' => 'AcmeBundle:MyClass'
just for the sake of the mock repository.
...
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);
}
}
Upvotes: 6
Reputation: 39390
You must implements the getExtensions
methods that build the two mocked form types used in the form: PlacesAutocompleteType
and EntityType
This solutions work for me:
<?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()));
}
}
Hope this help. Let me know.
Upvotes: 11