symfony – 在编写功能测试时将会话中的用户附加到当前的EntityManager

我正在为与User实体有关系的Action实体编写功能测试:

<?php

namespace Acme\AppBundle\Entity;

/**
 * Class Action
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Acme\AppBundle\Repository\ActionRepository")
 */
class Action
{
    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var \Acme\AppBundle\Entity\User
     *
     * @ORM\ManyToOne(targetEntity="\Acme\AppBundle\Entity\User", inversedBy="actions")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $createdBy;
}

用户:
    

namespace Acme\AppBundle\Entity;

/**
 * @ORM\Entity
 * @ORM\Table(name="`user`")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Action", mappedBy="createdBy")
     */
    private $actions;
}

并使用以下代码段在控制器中设置用户:

<?php

namespace Acme\ApiBundle\Controller;

/**
 *
 * @Route("/actions")
 */
class ActionController extends FOSRestController
{
    public function postAction(Request $request)
    {
        $action = new Action();
        $action->setCreatedBy($this->getUser());

        return $this->processForm($action, $request->request->all(), Request::METHOD_POST);
    }
}

例如,当使用REST客户端调用操作时,一切正常,Action和User之间的关系将被正确保留.

现在,在使用功能测试测试操作时,由于以下错误,关系无法正常工作:

A new entity was found through the relationship ‘Acme\AppBundle\Entity\Action#createdBy’ that was not configured to cascade persist operations for entity: test. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={“persist”}).

对于我的功能测试,我需要注入一个JWT和一个会话令牌,因为我的路由是由JWT保护的,我需要有一个用户在会话中.

这是我注入的方式:

<?php

namespace Acme\ApiBundle\Tests;

class ApiWebTestCase extends WebTestCase
{
    /**
     * @var ReferenceRepository
     */
    protected $fixturesRepo;

    /**
     * @var Client
     */
    protected $authClient;

    /**
     * @var array
     */
    private $fixtures = [];

    protected function setUp()
    {
        $fixtures = array_merge([
            'Acme\AppBundle\DataFixtures\ORM\LoadUserData'
        ], $this->fixtures);

        $this->fixturesRepo = $this->loadFixtures($fixtures)->getReferenceRepository();

        $this->authClient = $this->createAuthenticatedClient();
    }

    /**
     * Create a client with a default Authorization header.
     *
     * @return \Symfony\Bundle\FrameworkBundle\Client
     */
    protected function createAuthenticatedClient()
    {
        /** @var User $user */
        $user = $this->fixturesRepo->getReference('user-1');

        $jwtManager = $this->getContainer()->get('lexik_jwt_authentication.jwt_manager');
        $token = $jwtManager->create($user);

        $this->loginAs($user, 'api');

        $client = static::makeClient([], [
            'AUTHENTICATION' => 'Bearer ' . $token,
            'CONTENT_TYPE' => 'application/json'
        ]);

        $client->disableReboot();

        return $client;
    }
}

现在,问题是注入的UsernamePasswordToken包含一个与当前EntityManager分离的User实例,从而导致上面的Doctrine错误.

我可以将postAction方法中的$user对象合并到EntityManager中,但我不想这样做,因为这意味着我修改了我的工作代码以进行测试通过.
我也尝试将我的测试中的$user对象直接合并到EntityManager中,如下所示:

$em = $client->getContainer()->get('doctrine')->getManager();
$em->merge($user);

但它也没有用.

所以现在,我卡住了,我真的不知道该怎么做,除了我需要将会话中的用户附加回当前的EntityManager.

最佳答案 您收到的错误消息表明测试客户端容器中包含的EntityManager不知道您的用户实体.这让我相信您在createAuthenticatedClient方法中检索用户的方式是使用不同的EntityManager.

我建议你尝试使用测试内核的EntityManager来检索User实体.例如,您可以从测试客户端的容器中获取它.

点赞