【问题标题】:Manage entity IDs with data fixtures使用数据夹具管理实体 ID
【发布时间】:2017-01-22 15:45:53
【问题描述】:

我遇到了 Doctrine Data Fixtures 的问题:当我使用 Fixtures 插入一些数据以运行验收测试时,我能否以某种方式确保持久化的特定实体使用特定 ID 持久化?

例如,我创建了几个示例用户,然后运行验收测试编辑其中一个用户。我需要知道这个测试用例的用户 ID。 处理此问题的最佳做法是什么? 是否可以为固定装置创建的某些实体的 ID 进行硬编码,或者我应该将生成的 ID 存储到单独的表、文件等中以查找请求的实体?还是有其他最佳做法?

提前致谢。

【问题讨论】:

  • 你没有用 Symfony 标记你的问题,但在这里阅读:symfony.com/doc/current/bundles/DoctrineFixturesBundle/… 可能会给你一些想法。
  • 嗯,我没有,因为我不在那里使用 Symfony :) 我也将 Doctrine 用于 Nette 框架。但是,我最终还是采用了 Symfony 的方法,非常感谢 :)

标签: doctrine-orm doctrine fixtures


【解决方案1】:

在我们的应用程序中,我们将实体设置为这些固定装置的静态属性,以便可以轻松地在测试中使用它们。

class CategoryTestFixture
    extends \Doctrine\Common\DataFixtures\AbstractFixture
    implements 
        \Doctrine\Common\DataFixtures\OrderedFixtureInterface,
        \Symfony\Component\DependencyInjection\ContainerAwareInterface
{

    /** @var \My\Category */
    public static $fooCategory;

    /** @var \My\Category */
    public static $barCategory;

    /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
    private $container;

    public function load(ObjectManager $manager)
    {
        self::$fooCategory = new Category('Foo');
        $entityManager->persist(self::$fooCategory);

        self::$barCategory = new Category('Bar');
        $entityManager->persist(self::$barCategory);

        $entityManager->flush();
    }

    // you can inject the container,
    // so you can use your Facades in fixtures

    public function getContainer(): ContainerInterface
    {
        return $this->container;
    }

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

}

这有几个重要的规则:

  • 确保您没有在您的灯具中调用$em->clear(),这样您就可以直接使用其他灯具类中的实体。
  • 一旦加载了固定装置,请致电$em->clear(),这样它们就不会影响您的测试。
  • 在每次测试之前,复制准备好的数据库并将该副本用于您的测试,而不是“模板数据库”。因此您可以安全地修改数据。它可以进一步优化,但这是最直接的解决方案。
  • 不要在测试中合并或尝试注册为托管的原始设备。

现在您已经创建了固定装置,您可以像这样使用它们

$id = CategoryTestFixture::$barCategory->getId();

此外,您可以引用它们的所有属性,而不仅仅是 id。因此,如果您想断言,您的 api 返回了正确的类别,您可以这样做。

$this->assertArraySubset([
    [
        'id' => CategoryTestFixture::$fooCategory->getId(),
        'name' => CategoryTestFixture::$fooCategory->getName(),
    ],
    [
        'id' => CategoryTestFixture::$barCategory->getId(),
        'name' => CategoryTestFixture::$barCategory->getName(),
    ]
], $apiResponseData);

如果您只想为一个测试用例修改数据,请使用夹具的属性来修改数据库,然后清除 EM,这样您就不会在实体管理器中使用已经填充的身份映射创建副作用。

$barCategory = $entityManager->find(
    Category::class,
    CategoryTestFixture::$barCategory->getId()
);

$barCategory->setName('Another name');

$entityManager->flush();
$entityManager->clear();

【讨论】:

  • 有趣的想法,但我不认为这比 Symfony 的引用方法更好。我也不太明白清除 EM 有什么帮助,不应该已经加载的实体已经被 Doctrine 正确映射,所以如果我从引用修改它,所有其他引用(“引用变量”)都指向相同的修改实体?
猜你喜欢
  • 2023-02-08
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 2018-09-06
相关资源
最近更新 更多