3

我整天都在尝试为解析自定义 DSL 并创建 DQL 查询的类编写一些测试。

我的班级要求我传入 aqueryBuilder然后它用于构建查询并返回它。

我的问题是

  • 得到一个queryBuilder我需要一个entityManager
  • 得到一个entityManager我需要一个连接
  • 要获得连接,我需要一个数据库

我宁愿我的单元测试不依赖于数据库,所以我一直在尝试使用创建模拟queryBuilderPHPUnitqueryBuilder似乎依赖于entityManager后者又依赖于连接。

所以 2 个问题:
有没有更好的方法在 Doctrine 2 中动态构造查询?
有没有办法在queryBuilder没有entityManager(或至少没有真正的数据库)的情况下工作?

4

2 回答 2

3

我不确定如何使用 PHPUnit,但我建议您查看Mockery以满足您的 PHP 模拟需求。它是一个非常强大的库,它允许您非常轻松地模拟 EntityManager,因此它会返回任何东西。

对于您的用例,您可以轻松地创建一个模拟实体管理器,而不是返回一个模拟查询构建器:

$mockEm = \Mockery::mock('\Doctrine\ORM\EntityManager');
$mockQb = \Mockery::mock('\Doctrine\ORM\QueryBuilder');
$mockEm->shouldReceive('createQueryBuilder')->andReturn($mockQb);

然后,您可以使用 Mockery 的核心功能来设置单元测试所需的期望。

顺便说一句,您还可以选择使用“被动”EntityManager 模拟,以防您想对包含一些数据库逻辑的函数进行单元测试,但您实际上并不想在单元测试中进入数据库.

public function getPassiveEntityManagerMock() {
    return \Mockery::mock('\Doctrine\ORM\EntityManager',
                          array('getRepository' => new FakeRepository(),
                                'getClassMetadata' => (object)array('name' => 'aClass'),
                                'persist' => null,
                                'flush' => null));
}

这是使用 PHPUnit 的建议方法,但我自己还没有尝试过。

于 2013-02-08T15:11:05.997 回答
1

我最终创建了自己的模拟查询构建器;使用 PHPUnits 模拟框架可能获得相同的功能,但这就是我最终得到的结果:

<?php
namespace MyNameSpace\Tests\Mocks;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Common\Collections\ArrayCollection;

class MockQueryBuilder extends QueryBuilder {

    protected $expr;
    protected $paramReflect;

    public function __construct($expr) {
        $this->expr = $expr;
        $this->paramReflect = new \ReflectionProperty('Doctrine\ORM\QueryBuilder', 'parameters'); 
        $this->paramReflect->setAccessible(true);
        $this->paramReflect->setValue($this, new ArrayCollection());
    }

    /*
     * @return Query\Expr
     */
    public function expr() {
        return $this->expr;
    }

    public function getEntityManager() {
        return null;
    }

    public function getQuery() {
        return array(
            'parameters' => clone $this->paramReflect->getValue($this),
            'dql' => $this->getDQL(),

        );
    }

}
于 2013-02-08T14:40:05.617 回答