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

Fox*_*ion 13 testing phpunit mocking symfony doctrine-orm

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

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

$name = $entity->getProperty(); // OK
$id = $entity->getId(); // not OK - null
Run Code Online (Sandbox Code Playgroud)

我所知道的决议:

  1. 初始化整个内核(Symfony的WebTestCase :: createKernel())并持久化实体
  2. 为每个实体创建一个模拟对象,它将返回有效的ID
  3. 黑客像TheEntity类中的静态方法返回初始化对象,或添加id字段的setter

建议的处理方法是什么,如何使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Nik*_*car 9

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

示例:

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

    $property->setValue($entity, $value);
}
Run Code Online (Sandbox Code Playgroud)

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


Nic*_*ich 7

您可以配置doctrine以在您的内存中使用内存数据库app/config/config_test.yml.

# app/config/config_test
doctrine:
    dbal:
        driver: pdo_sqlite
        path: :memory:
        memory: true
Run Code Online (Sandbox Code Playgroud)

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

你可以在这个答案这篇博文中找到一些灵感.


And*_*tye 5

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

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

       return $this;
    }
}
Run Code Online (Sandbox Code Playgroud)

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