如何创建具有Doctrine实体的测试而不持久化它们(如何设置id)

时间:2013-10-14 19:59:44

标签: symfony testing doctrine-orm mocking phpunit

我正在为Symfony2项目进行测试,现在我正在寻找一种方法来创建涉及实体对象的测试而不会持久化它们。问题是: id 是一个私有字段,没有setter。我可以创建新对象并设置一些属性,但我无法测试涉及 getId()调用的任何内容。

$entity = new TheEntity();
// Can't set ID!
$entity->setProperty('propertyValue');

$name = $entity->getProperty(); // OK
$id = $entity->getId(); // not OK - null

我知道的决议:

  1. 初始化整个内核(Symfony的 WebTestCase :: createKernel())并持久保存实体
  2. 为每个实体创建一个模拟对象,它将返回有效ID
  3. TheEntity 类中的静态方法一样,返回初始化对象,或为 id 字段添加setter
  4. 建议的处理方法是什么,如何使用set ID以干净,快速的方式获取实体进行测试?

    修改

    原来我可以用嘲笑来解决这个问题...对不起,我还在学习。我一直在寻找一种干净,标准,快速的方法来完成任务。但是我忘记了getMock()的第二个参数 - 那就是我不必模拟我将要使用的实体的每个方法。我想避免多个->expects()->method()->will()等。这可以通过添加:array('getId')来实现。这个辅助方法解决了这个问题:

    protected function getEntityMock($entityClass, $id)
    {
        $entityMock = $this->getMock($entityClass, array('getId'));
        $entityMock
                ->expects($this->any())
                ->method('getId')
                ->will($this->returnValue($id));
    
        return $entityMock;
    }
    

    当创建同一个类的许多实体时,事情当然可以通过更多辅助方法来简化,例如:

    protected function getTheEntityMock($id)
    {
        return $this->getEntityMock('\The\NameSpace\TheEntity', $id);
    }
    

    唯一的限制是实体本身不能使用id属性,只能使用getId() getter。

    仍然欢迎任何有价值的输入,但我相信PHPUnit的getMock()很好地解决了这个问题。

3 个答案:

答案 0 :(得分:9)

它有点旧,但值得一提的是,最好的方法是使用Reflection来改变那些受保护值的辅助方法。

示例:

public function set($entity, $value, $propertyName = 'id')
{
    $class = new ReflectionClass($entity);
    $property = $class->getProperty($propertyName);
    $property->setAccessible(true);

    $property->setValue($entity, $value);
}

将它放在您扩展的基础测试类中,或者在trait中使用它,并在测试中需要类似的东西时使用它。通过这种方式,您将能够编写测试而无需创建脏更改。

答案 1 :(得分:7)

您可以将学说配置为使用app/config/config_test.yml中的内存数据库。

# app/config/config_test
doctrine:
    dbal:
        driver: pdo_sqlite
        path: :memory:
        memory: true

这样可以加快这个过程,你可以在setUp()方法中快速保留一些灯具,这些灯具在刷新后会有(自动生成的)id ...而不会弄乱你的“真实”数据库。

您可以在this answerthis blog post找到一些灵感。

答案 2 :(得分:5)

另一种方法是创建一个实体的子项(如果你想保持干净,这可以存在于tests文件夹中),然后添加" setId()"孩子的方法

class TestableEntity extends \My\Namespace\Entity
{
    public function setId($id)
    {
       $this->id = $id;

       return $this;
    }
}

然后,您的测试应该测试TestableEntity,而不是真实实体。 只要" id" \ My \ Namespace \ Entity中的属性是受保护的,而不是私有的,可以通过TestableEntity设置。