Symfony 2 + Doctrine 2 + PHPUnit 3.5:闭包异常的序列化
Posted
技术标签:
【中文标题】Symfony 2 + Doctrine 2 + PHPUnit 3.5:闭包异常的序列化【英文标题】:Symfony 2 + Doctrine 2 + PHPUnit 3.5: Serialization of closure exception 【发布时间】:2011-05-20 23:27:07 【问题描述】:我试图在 Google 上找到有关此的内容,但没有任何结果。我有一个继承自 WebTestCase 的 TestCase 类,其中包含一些我想在所有单元/功能测试中使用的方法:
<?php
namespace Application\FaxServerBundle\Test;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Application\FaxServerBundle\DataFixtures\ORM\NetworkConfigurationData;
class TestCase extends WebTestCase
protected $kernel;
public function setUp()
parent::setUp();
public function getEm()
return $this->getService( 'doctrine.orm.entity_manager' );
public function getNetworkConfigurationRepository()
return $this->getEm()->getRepository( 'Application\FaxServerBundle\Entity\NetworkConfiguration' );
public function loadNetworkConfigurationFixtures()
$loader = new Loader();
$loader->addFixture( new NetworkConfigurationData() );
$this->loadFixtures( $loader );
public function loadFixtures( $loader )
$purger = new ORMPurger();
$executor = new ORMExecutor( $this->getEm(), $purger );
$executor->execute( $loader->getFixtures() );
protected function getService( $name, $kernel = null )
return $this->getBootedKernel()->getContainer()->get( $name );
protected function hasService( $name, $kernel = null )
return $this->getBootedKernel()->getContainer()->has( $name );
protected function getBootedKernel()
$this->kernel = $this->createKernel();
if ( !$this->kernel->isBooted() )
$this->kernel->boot();
return $this->kernel;
public function generateUrl( $client, $route, $parameters = array() )
return $client->getContainer()->get( 'router' )->generate( $route, $parameters );
然后,我的单元测试:
<?php
namespace Application\FaxServerBundle\Tests\Entity;
use Doctrine\ORM\AbstractQuery;
use Application\FaxServerBundle\Entity;
use Application\FaxServerBundle\Test\TestCase;
class NetworkConfigurationRepositoryTest extends TestCase
public function setUp()
parent::setUp();
$this->loadNetworkConfigurationFixtures();
public function testGetConfiguration()
$config = $this->getNetworkConfigurationRepository()->getConfigurationArray();
$this->assertInternalType( 'array', $config );
$this->assertEquals( 6, count( $config ) );
$this->assertArrayHasKey( 'id', $config );
$this->assertArrayHasKey( 'ip', $config );
$this->assertArrayHasKey( 'gateway', $config );
$this->assertArrayHasKey( 'subnetMask', $config );
$this->assertArrayHasKey( 'primaryDns', $config );
$this->assertArrayHasKey( 'secondaryDns', $config );
public function testGetConfigurationObject()
$config = $this->getNetworkConfigurationRepository()->getConfigurationObject();
$this->assertInternalType( 'object', $config );
public function testGetConfigurationArray()
$config = $this->getNetworkConfigurationRepository()->getConfigurationArray();
$this->assertInternalType( 'array', $config );
它以前可以工作,但是,突然,在我更新了我的供应商(包括原则)之后,它开始抛出这个异常:
3) Application\FaxServerBundle\Tests\Entity\NetworkConfigurationRepositoryTest::testGetConfigurationArray
RuntimeException: PHP Fatal error: Uncaught exception 'PDOException' with message 'You cannot serialize or unserialize PDO instances' in -:32
Stack trace:
#0 [internal function]: PDO->__sleep()
#1 -(32): serialize(Array)
#2 -(113): __phpunit_run_isolated_test()
#3 main
Next exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in -:0
Stack trace:
#0 -(0): serialize()
#1 -(113): __phpunit_run_isolated_test()
#2 main
thrown in - on line 0
我发现问题来自于夹具加载。如果我删除加载固定装置的代码,它就可以工作。
有人知道我的代码有什么问题吗?这是加载夹具的最佳方式吗?
谢谢!
【问题讨论】:
【参考方案1】:你也可以试试。
<phpunit backupGlobals="false">
<testsuites>
<testsuite name="Test">
<directory>.</directory>
</testsuite>
</testsuites>
</phpunit>
【讨论】:
【参考方案2】:在技术上与您的问题无关。但是,在使用 PHPUnit 时,我很难解决“不允许序列化 'Closure'”的问题,而这个问题是 Google 的最高结果。
问题在于 PHPUnit 将系统中的所有 $GLOBALS 序列化,以便在测试运行时对它们进行必要的备份。然后在测试完成后恢复它们。
但是,如果您的 GLOBAL 空间中有任何闭包,则会导致问题。有两种方法可以解决。
您可以使用注释完全禁用全局备份过程。
/**
* @backupGlobals disabled
*/
class MyTest extends PHPUnit_Framework_TestCase
// ...
或者,如果您知道是哪个变量导致了问题(在 var_dump($GLOBALS) 中查找 lambda),您可以将问题变量列入黑名单。
class MyTest extends PHPUnit_Framework_TestCase
protected $backupGlobalsBlacklist = array('application');
// ...
【讨论】:
感谢您的回答!这确实是我为了解决这个例外的大部分问题而必须做的。在我的测试中,我唯一遇到的问题显然来自 Symfony 2 的 Validator 组件。可悲的是,我无法弄清楚它为什么会发生。 这似乎已在 PHPUnit 3.6 中修复:github.com/sebastianbergmann/phpunit/pull/352 这也可以通过命令开关phpunit --no-globals-backup
(phpunit.de/manual/3.6/en/textui.html) 或通过phpunit.xml
文件<phpunit backupGlobals="false" />
(phpunit.de/manual/3.6/en/…) 中的相应属性对所有测试完成。
另外避免 --process-isolation 选项,它会导致“不允许序列化'Closure'”。使用 PHPUnit 3.7 测试
我遇到了与--process-isolation
相关的问题 - 看起来 PHPUnit 也尝试序列化通过数据提供程序传入的对象,即使您使用 --no-globals-backup
也无法阻止此操作。我不得不重新设计我的数据提供者并进行测试以解决这个问题。以上是关于Symfony 2 + Doctrine 2 + PHPUnit 3.5:闭包异常的序列化的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Symfony 2 / Doctrine 中启用 ENUM
Symfony 2 - Doctrine 2 - Native Sql - 删除查询
Symfony 和 Doctrine 1.2.2:如何获取 Doctrine_Query 对象的 SQL 子句?