我对Symfony FormType测试提出了一个问题。 http://symfony.com/doc/current/cookbook/form/unit_testing.html
在我的表单类型中,entity
类型很常见。使用doctrine实体表单类型测试表单类型是可怕的。
这是我的表格领域。
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('products', 'entity', array(
'class' => 'AcmeDemoBundle:Product',
'label' => 'Product',
'property' => 'name',
'required' => false,
'mapped' => true,
'multiple' => true,
'expanded' => true
));
}
这是该领域的模拟。
private function getEntityTypeMock()
{
$entityRepositoryMock = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock()
;
$entityRepositoryMock->expects($this->once())
->method('findAll')
->will($this->returnValue(array()));
$classMetaDataMock = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')
->disableOriginalConstructor()
->getMock();
$mockEntityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue($classMetaDataMock));
$mockEntityManager->expects($this->once())
->method('getRepository')
->will($this->returnValue($entityRepositoryMock));
$mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->getMock();
$mockRegistry->expects($this->any())
->method('getManagerForClass')
->will($this->returnValue($mockEntityManager));
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->setMethods(array('getName'))
->setConstructorArgs(array($mockRegistry))
->getMock();
$mockEntityType->expects($this->any())->method('getName')
->will($this->returnValue('entity'));
return $mockEntityType;
}
这真的是正确的方法吗?在TypeTestCase
内部,我无法访问任何内容,没有容器没有内核,没有任何内容。这使得测试表单类型非常困难和令人沮丧。
有没有更好的方法来测试表单类型?或者更简单的方法来处理具有ORM依赖性的类型?
干杯。
我一直在努力进行单元测试,这些东西依赖于服务容器。起初我像你一样试图嘲笑一切。这可以使单元测试通过很大的努力(服务倾向于依赖于Symfony中的其他服务,这也将不得不被模拟),但是需要更多的努力来确保通过测试意味着它会使用您希望它使用的数据。
另外,单元测试数据库是众所周知的困难,很少讨论。我不确定我所分享的内容是否是“最佳”答案,但这是一个对我有用的答案,它有助于对真实服务进行单元测试。因此,我发现它是一种更有效的测试方法,而不是模拟服务。
这是基于一篇伟大的文章,当然,我现在找不到(如果我发现它可以归功于它,我会更新)。
基本上,您可以设置捆绑包以使容器进行测试。
composer.json:
"require-dev": {
"sensio/framework-extra-bundle": ">=3.0",
"symfony/asset": ">=3.2"
}
然后创建一个config.yml
,其中包含您可能需要的任何服务以及Symfony表单的最低限度:
framework:
secret: 'shh'
form: ~
validation: { enable_annotations: true }
session:
storage_id: session.storage.mock_file
doctrine:
# your doctrine settings if you want to test against the DB
创建一个AppKernel类。
class AppKernel extends Kernel
{
public function registerBundles()
{
return array(
new FrameworkBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
// any other bundles you need
);
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config.yml');
}
public function getLogDir()
{
return '/tmp/log/' . $this->environment;
}
}
最后,我在我的基础TestCase中创建了一个帮助器类:
protected function getContainer()
{
if (!isset($this->kernel)) {
$this->kernel = new AppKernel('test', true);
$this->kernel->boot();
}
if (!isset($this->container)) {
$this->container = $this->kernel->getContainer();
}
return $this->container;
}
现在,您可以访问已注册的任何服务,如下所示:
public function testContainerAccess()
{
$this->assertTrue(is_object($this->getContainer());
$this->assertTrue($this->getContainer()->get('doctrine.orm.entity_manager') instanceof \Doctrine\ORM\EntityManagerInterface);
}
对数据库进行测试总是很棘手,并且是一个单独的蠕虫病毒。在这种情况下,最简单的方法可能是创建一个单独的测试模式并针对该模式运行查询。
希望这可以帮助。