Zend Framework 2:如何在phpunit的单元测试中包含Doctrine2支持?

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中。我努力寻找好的例子

在进一步研究之后,我将重新表述我的问题:如何模拟Doctrine2的实体管理器进行单元测试,特别是在控制器中?本质上,我需要进行单元测试,并用Doctrine2的实体管理器替换与模拟TableGateway相关的任何内容


(原员额)

不久前,我阅读了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');
    }