Symfony Doctrine 关系在 PhpUnit 测试中为空

Posted

技术标签:

【中文标题】Symfony Doctrine 关系在 PhpUnit 测试中为空【英文标题】:Symfony Doctrine relationship empty in PhpUnit test 【发布时间】:2021-06-30 07:39:38 【问题描述】:

我有一个带有 User 实体的 Symfony 应用程序,该实体与 Cat 实体具有多对多关系。我还有一个 phpUnit 测试,它检查从 1 个用户删除一只猫(属于 2 个用户)实际上并没有删除猫:

    public function testDeletingACatBelongingToTwoUsersOnlyDeletesTheAssociationNotTheCat()
    
        $cat = $this->createCat();
        // Associate with user 1
        $user1 = new User();
        $user1->setEmail('test@example.com');
        $user1->setPassword('pwdpwd');
        $user1->addCat($cat);
        $this->em->persist($user1);
        // Associate with user 2
        $user2 = new User();
        $user2->setEmail('another@example.com');
        $user2->setPassword('pwdpwd');
        $user2->addCat($cat);
        $this->em->persist($user2);
        $this->em->flush();
        // Sanity check:
        $this->assertCount(1, $user1->getCats()); // PASS
        $this->assertCount(1, $user2->getCats()); // PASS
        $this->assertCount(2, $cat->getUsers()); // FAIL (0)
        // ... perform the test (not shown here)
    

    private function createCat(): Cat
    
        $cat = new Cat();
        $cat->setName($this->name);
        $this->em->persist($cat);
        $this->em->flush();

        return $cat;
    

我的问题是,为什么$cat->getUsers() 在我的测试中返回0?在运行时它不会,它返回正确的值。只有在测试中才会返回0

以下是我的实体的相关摘录,由 Symfony 自动生成:

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
class User implements UserInterface

    /**
     * @ORM\ManyToMany(targetEntity=Cat::class, inversedBy="users")
     */
    private $cats;

    /**
     * @return Collection|Cat[]
     */
    public function getCats(): Collection
    
        return $this->cats;
    

    public function addCat(Cat $cat): self
    
        if (!$this->cats->contains($cat)) 
            $this->cats[] = $cat;
        

        return $this;
    

    public function removeCat(Cat $cat): self
    
        $this->cats->removeElement($cat);

        return $this;
    


/**
 * @ORM\Entity(repositoryClass=CatRepository::class)
 */
class Cat

    /**
     * @ORM\ManyToMany(targetEntity=User::class, mappedBy="cats")
     */
    private $users;

    /**
     * @return Collection|User[]
     */
    public function getUsers(): Collection
    
        return $this->users;
    

【问题讨论】:

我们通常只使用Mockery 来处理类似的事情。您可以根据需要模拟 EntityManager 并让它返回您需要的内容。这样你是在测试你的实际逻辑,而不是 EM 本身。 【参考方案1】:

原因是,集合没有与数据库同步,拥有方和反向方之间的同步也不会自动完成。

您的用户实体的类别条目可能将被持久化到数据库中(虽然我缺少一些级联语句,但我知道什么)。创建类别时,它的用户集合是空的(显然),然后用户将类别添加到数据库中的多对多关系中。

但是,这个集合是一个普通的集合。如果您从数据库加载类别,它将是一个延迟加载的 PersistentCollection(或类似的东西),它只会在访问时从数据库中获取项目(延迟加载的定义)。您的测试代码具有普通集合(因为您自己创建了对象)。

不太确定,如果它会起作用,但你可以尝试刷新猫 ($em->refresh($cat);) 不过我不太确定,如果它会替换集合。或者,您可以将 User::addCat 设为它也调用 $cat->addUser($this)(您可能需要添加它,注意无限递归,“包含”检查应该已经阻止了它。)。

【讨论】:

谢谢 - refresh 工作。这也是一个有用的解释为什么普通的集合没有水合。

以上是关于Symfony Doctrine 关系在 PhpUnit 测试中为空的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 和 Doctrine:一对多关系

Symfony Doctrine 关系在 PhpUnit 测试中为空

Symfony 5,Doctrine queryBuilder OneToMany 关系

Symfony Doctrine 关系 - 删除反面的实体

Symfony 2 与 Doctrine 中的一对多关系

使用 Doctrine 和 Symfony2 查询多对多关系