Zend Framework 2:如何在phpunit的单元测试中包含Doctrine2支持?
在进一步研究之后,我将重新表述我的问题:如何模拟Doctrine2的实体管理器进行单元测试,特别是在控制器中?本质上,我需要进行单元测试,并用Doctrine2的实体管理器替换与模拟TableGateway相关的任何内容Zend Framework 2:如何在phpunit的单元测试中包含Doctrine2支持?,php,doctrine-orm,zend-framework2,phpunit,Php,Doctrine Orm,Zend Framework2,Phpunit,在进一步研究之后,我将重新表述我的问题:如何模拟Doctrine2的实体管理器进行单元测试,特别是在控制器中?本质上,我需要进行单元测试,并用Doctrine2的实体管理器替换与模拟TableGateway相关的任何内容 (原员额) 不久前,我阅读了2.1版的官方ZF2入门教程并完成了它,然后又阅读了关于单元测试的附加教程。 在完成这些教程之后,我得出结论,Zend_Db不太可能优雅地处理我的应用程序需求,因此开始考虑将条令2集成并使用到Zend Framework 2中。我努力寻找好的例子
(原员额) 不久前,我阅读了2.1版的官方ZF2入门教程并完成了它,然后又阅读了关于单元测试的附加教程。 在完成这些教程之后,我得出结论,Zend_Db不太可能优雅地处理我的应用程序需求,因此开始考虑将条令2集成并使用到Zend Framework 2中。我努力寻找好的例子,然后找到了下面的教程,这是一个很好的开始。 正是在这里,我挂断了电话,因为我想在我的单元测试中加入第2条原则的变更,但却不知道如何进行。经过几天毫无成果的研究,我把这个项目搁置了一段时间,现在又回来了。我找到了关于这个主题的另一个不错的教程,但是它涉及ZF1,所以结构有很大的不同。 然而,通过对我的示例ZF2文件与ZF1框架相关文件的比较,我发现至少我可能需要在phpunit引导文件中设置条令实体管理器,然后在控制器测试中正确调用它 当前,当我运行phpunit时,我得到以下错误:
There was 1 failure:
1) AlbumTest\Controller\AlbumControllerTest::testEditActionRedirectsAfterValidPost
Expectation failed for method name is equal to <string:find> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
(我真的不确定这里的“Album\Entity\Album”是否正确,但我的理解是,由于原则2,我不再使用我在初始教程中创建的“Album\Models\Album”或“Album\Models\AlbumTable”。)
在AlbumController中,代码的相关部分如下所示:
// Get the Album with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try {
//$album = $this-> getAlbumTable()->getAlbum($id); // Zend_DB
$album = $this->getEntityManager()->find('Album\Entity\Album', $id); // Doctrine
}
所以我这里的主要问题是如何设置phpunit引导文件以包含Doctrine2
(增编) 现在我将回到上面的场景,但目前我正在尝试为我的测试成功地模拟实体管理器,我已经在我的控制器测试中注释掉了上面的getmock,以了解基本情况。我已经为Album\Entity\Album设置了一个基本的测试,所以我认为我的引导是可以的,但是我现在失败了,因为在使用
$this->dispatch()
时,测试试图从控制器访问数据库,这是我不想要的
PHPUnit故障:
1) AlbumTest\Controller\AlbumControllerTest::testIndexActionCanBeAccessed
PDOException: SQLSTATE[HY000] [1045] Access denied for user 'username'@'localhost' (using password: YES)
我没有在任何地方显式定义此用户,因此我猜测没有找到或加载配置文件,但我还是想模拟数据库连接
这是我的测试引导:
<?php
namespace AlbumTest;
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
//use DoctrineORMModuleTest\Framework\TestCase;
//use Doctrine\Tests\Mocks;
use RuntimeException;
error_reporting(E_ALL | E_STRICT);
chdir(__DIR__);
// Set timezone or PHPUnit reports error
date_default_timezone_set('America/Chicago');
/**
* Test bootstrap, for setting up autoloading
*/
class Bootstrap
{
protected static $serviceManager;
protected static $em; // Doctrine
public static function init()
{
$zf2ModulePaths = array(dirname(dirname(__DIR__)));
if (($path = static::findParentPath('vendor'))) {
$zf2ModulePaths[] = $path;
}
if (($path = static::findParentPath('module')) !== $zf2ModulePaths[0]) {
$zf2ModulePaths[] = $path;
}
static::initAutoloader();
// use ModuleManager to load this module and it's dependencies
$config = array(
'module_listener_options' => array(
'module_paths' => $zf2ModulePaths,
),
'modules' => array(
'DoctrineModule',
'DoctrineORMModule',
'Album'
)
);
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $config);
$serviceManager->get('ModuleManager')->loadModules();
static::$serviceManager = $serviceManager;
static::$em = self::getEntityManager($serviceManager); // Doctrine
}
public static function getServiceManager()
{
return static::$serviceManager;
}
public static function getEntityManager($serviceManager)
{
return $serviceManager->get('Doctrine\ORM\EntityManager');
}
protected static function initAutoloader()
{
$vendorPath = static::findParentPath('vendor');
$zf2Path = getenv('ZF2_PATH');
if (!$zf2Path) {
if (defined('ZF2_PATH')) {
$zf2Path = ZF2_PATH;
} else {
if (is_dir($vendorPath . '/ZF2/library')) {
$zf2Path = $vendorPath . '/ZF2/library';
}
}
}
if (!$zf2Path) {
throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.');
}
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
),
),
));
}
protected static function findParentPath($path)
{
// This function traverses up from the working directory
// until it finds the parent of the named path
// (used to find 'vendor' parent in initAutoloader).
$dir = __DIR__;
$previousDir = '.';
while (!is_dir($dir . '/' . $path)) {
$dir = dirname($dir);
if ($previousDir === $dir) return false;
$previousDir = $dir;
}
return $dir . '/' . $path;
}
}
Bootstrap::init();
<?php
namespace AlbumTest\Controller;
//use Album\Models\Album;
use Album\Entity\Album;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
use Zend\Db\ResultSet\ResultSet;
//use PHPUnit_Framework_TestCase;
class AlbumControllerTest extends AbstractHttpControllerTestCase
{
protected $traceError = true;
public function setUp()
{
// Need to mock entity manager for doctrine use
$this->em = $this->getMock('EntityManager', array('persist', 'flush', 'find','getClassMetaData','getRepository'));
$this->em
->expects($this->any())
->method('persist')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('flush')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('find')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('getRepository')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue((object)array('name' => 'aClass')));
$this->doctrine = $this->getMock('Doctrine', array('getEntityManager'));
$this->doctrine
->expects($this->any())
->method('getEntityManager')
->will($this->returnValue($this->em));
$this->setApplicationConfig(
include __DIR__ . '../../../../../../config/application.config.php'
);
parent::setUp();
}
public function testIndexActionCanBeAccessed()
{
//$albumTableMock = $this->getMockBuilder('Album\Models\AlbumTable')
$albumTableMock = $this->getMockBuilder('Album\Entity\Album')
->disableOriginalConstructor()
->getMock();
$albumTableMock->expects($this->once())
//->method('fetchAll')
->method('findAll')
->will($this->returnValue(array()));
$serviceManager = $this->getApplicationServiceLocator();
$serviceManager->setAllowOverride(true);
$serviceManager->setService('Album\Entity\Album', $albumTableMock);
$this->dispatch('/album');
$this->assertResponseStatusCode(200);
$this->assertModuleName('Album');
$this->assertControllerName('Album\Controller\Album');
$this->assertControllerClass('AlbumController');
$this->assertMatchedRouteName('album');
}
您需要对数据库测试用例使用GenericTestsDatabaseTestCase,并且需要在数据库测试用例类中提供xml格式的mysql转储文件作为dataset。因此,在单元测试期间,应用程序不会查询实际数据库,而是查询mysql xml转储。其他事项,如条令实体中的例外/错误(如果没有任何匹配列等)。。就这样吧。简而言之,由于数据集[database xml dump file]的原因,doctine将对xml数据集文件而不是实际数据库进行查询。我不知道Zend的情况,但Symfony 2有一个WebTestCase,您可以扩展它。然后,web测试用例允许您访问依赖项注入容器,您可以从中提取doctrine 2实体管理器和存储库。在Zend 2中寻找类似的东西。或者交换框架。
<?php
namespace AlbumTest\Entity;
use Album\Entity\Album;
use PHPUnit_Framework_TestCase;
class AlbumTest extends PHPUnit_Framework_TestCase
{
public function testAlbumInitialState() {
$album = new Album();
$this->assertNull($album->artist, '"artist" should initially be null');
$this->assertNull($album->id, '"id" should initially be null');
$this->assertNull($album->title, '"title" should initially be null');
}
}
<?php
namespace AlbumTest\Controller;
//use Album\Models\Album;
use Album\Entity\Album;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
use Zend\Db\ResultSet\ResultSet;
//use PHPUnit_Framework_TestCase;
class AlbumControllerTest extends AbstractHttpControllerTestCase
{
protected $traceError = true;
public function setUp()
{
// Need to mock entity manager for doctrine use
$this->em = $this->getMock('EntityManager', array('persist', 'flush', 'find','getClassMetaData','getRepository'));
$this->em
->expects($this->any())
->method('persist')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('flush')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('find')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('getRepository')
->will($this->returnValue(true));
$this->em
->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue((object)array('name' => 'aClass')));
$this->doctrine = $this->getMock('Doctrine', array('getEntityManager'));
$this->doctrine
->expects($this->any())
->method('getEntityManager')
->will($this->returnValue($this->em));
$this->setApplicationConfig(
include __DIR__ . '../../../../../../config/application.config.php'
);
parent::setUp();
}
public function testIndexActionCanBeAccessed()
{
//$albumTableMock = $this->getMockBuilder('Album\Models\AlbumTable')
$albumTableMock = $this->getMockBuilder('Album\Entity\Album')
->disableOriginalConstructor()
->getMock();
$albumTableMock->expects($this->once())
//->method('fetchAll')
->method('findAll')
->will($this->returnValue(array()));
$serviceManager = $this->getApplicationServiceLocator();
$serviceManager->setAllowOverride(true);
$serviceManager->setService('Album\Entity\Album', $albumTableMock);
$this->dispatch('/album');
$this->assertResponseStatusCode(200);
$this->assertModuleName('Album');
$this->assertControllerName('Album\Controller\Album');
$this->assertControllerClass('AlbumController');
$this->assertMatchedRouteName('album');
}