liip / LiipFunctionalTestBundle

Some helper classes for writing functional tests in Symfony

Home Page:http://liip.ch

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Association not hydrated when using getter on entity load by fixtures

mathieu-ducrot opened this issue · comments

Hello, i tried to find if this issue was already mentioned but i didn't found something that matchs my case.

I'm loading some entities with the loadFixtureFiles method, get the entity i would like to test from his repository.
Then i try to assert some getter from that entity that have association which are empty but should return data loaded by the fixtures.

Preconditions

I know i'm on an old version of these dependencies but i can't upgrade my dependancies because it's a production project that i can't aford to do it at the moment.

Here is my stack :

  • symfony/symfony 2.8.51
  • doctrine/orm 2.4.8
  • doctrine/dbal 2.7.2
  • liip/functional-test-bundle 1.11.0
  • nelmio/alice 2.3.5
  • php 7.1

Steps to reproduce

My entities :

class Condition
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="CriteriaInCondition", mappedBy="condition")
     */
    private $criteriaInCondition;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->criteriaInCondition = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * @return \Doctrine\Common\Collections\ArrayCollection
     */
    public function getCriteriaInCondition()
    {
        return $this->criteriaInCondition;
    }
class CriteriaInCondition
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id_cc", type="integer", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="operator", type="string", length=2, nullable=true)
     */
    private $operator;

    /**
     * @var float
     *
     * @ORM\Column(name="value", type="float", precision=10, scale=0, nullable=true)
     */
    private $value;

    /**
     * @var Condition
     *
     * @ORM\ManyToOne(targetEntity="Condition", inversedBy="criteriaInCondition")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="id_condition", referencedColumnName="id", nullable=false, onDelete="CASCADE")
     * })
     */
    private $condition;

    /**
     * @var Criteria
     *
     * @ORM\ManyToOne(targetEntity="Criteria", inversedBy="criteriaInCondition")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="id_critere", referencedColumnName="id", nullable=false, onDelete="CASCADE")
     * })
     */
    private $criteria;

The test

class ConditionTest extends AbstractWebTestCase
{
    /**
     * {@inheritDoc}
     */
    protected function setUp()
    {
        $this->loadFixtureFiles(
            $this->getParametersFixturePath(),
            false,
            null,
            'doctrine',
            ORMPurger::PURGE_MODE_TRUNCATE
        );
    }

    public function testGetCriteria()
    {
        $repository = $this->getConditionRepository();
        // load a condition with no criteria
        $this->loadFixtureFiles([$this->getFixtureDir() . '/condition/condition_without_criteria.yml'], true);
        $this->assertEquals(1, $repository->count());
        $condition = $repository->findByName('cond_without_criteria');
        $this->assertEquals([], $condition->getCriteriaInCondition());

        // load a condition with a criteria
        $this->loadFixtureFiles([$this->getFixtureDir() . '/condition/condition_with_criteres.yml'], true);
        $this->assertEquals(2, $repository->count());

        $condition = $repository->findByName('cond_with_one_criteria');
        $this->assertEquals(1, count($condition->getCriteriaInCondition()));
    }
}

AbstractWebTestCase is just an extend from the Liip\FunctionalTestBundle\Test\WebTestCase but with some fixtures path and repository method.

Expected result

The database is well loaded and the assert are correct.

Actual result

The database is well loaded but the last assertEquals on the getCriteriaInCondition method isn't true.

When i debug the situation with Debug::dump($condition->getCriteriaInCondition()); it is actually empty (it's like lazy relation aren't loaded).

Copy pasting the code in an action from a controller works fine though. Is there something i'm missing about the loading on the fixture or maybe some hydration config that i forget ?

I would be very happy if you could help me.

Thanks a lot,

Mathieu Ducrot.

To help you understand my issue and for a better testing situation i made a repository https://github.com/mathieu-ducrot/liip-load-fixture-files-test which recap the Steps to reproduce in a more detail way.

You can clone the repo and follow the README to view the process and the implementation that i have that cause my issue about association not hydrated.

I hope this will help you to better understand what's going on.

Well i'm back with some good news.

I had a similar case this week on a much recent version of liip/test-fixtures-bundle and it made me realise the real problem.
In fact it has nothing to deal with the bundle.

The behavior that trigger the issue was due to :

  • Doctrine first store the Inversed Entity (i.e Condition in the test) with 0 associations in his Identity Map while parsing the yml fixture with Alice
  • Then the Mapped Entity (i.e. CriteriaInCondition) is loaded by Doctrine and Alice
  • And at the moment the test actually run, Doctrine already has the Condition Proxies in his Identity Map so that why the association was always not hydrated when retrieve from the database (other simple exemple in doc form doctrine identity map)

So today i tried to get back to the old repo that i gave you with the specific version that didn't work.
And, as expected, i manage to successfully pass the test in Travis CI just by calling synchronous update on the setter from the mapped CriteriaInCondition Entity (and adding the missing method addCriteriaInCondition on the Inversed Condition Entity)

https://travis-ci.org/github/mathieu-ducrot/liip-load-fixture-files-test/builds/768239757
As you can see it's all green :)

(for those how want to see the change i did in my test to make it work: mathieu-ducrot/liip-load-fixture-files-test@8f886ac)

So yeah my bad for missing this but better late than never.

I'm closing the issue since everything is ok now.

Have a good day !