Тестирование светильников с помощью addReference в Symfony 4 - PullRequest
1 голос
/ 25 октября 2019

Я работаю над проектом Symfony, и у меня есть некоторые проблемы при тестировании с phpunit.

У меня есть StatusFixtures с addReference для использования в BriefFixtures, и это правильно работает, когда я делаю doctrine:fixtures:load (с правильной зависимостью для загрузки Status перед Brief). Но когда я запускаю свои тесты, используя эти приборы, появляется следующая ошибка: Error: Call to a member function addReference() on null

My StatusFixtures.php

<?php

namespace App\DataFixtures;

use App\Entity\Status;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;

class StatusFixtures extends Fixture
{
    const Status_Reference = 'status';

    public function load(ObjectManager $manager)
    {
        // some code to assign values

        $manager->persist($activeStatus);
        $this->addReference(self::Status_Reference, $activeStatus);
        $manager->flush();
    }
}

My BriefFixtures.php

<?php

namespace App\DataFixtures;

use App\Entity\Brief;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;

class BriefFixtures extends Fixture implements DependentFixtureInterface
{
    public function load(ObjectManager $manager)
    {
        // some code to assign values
        $briefValid->setStatus($this->getReference(StatusFixtures::Status_Reference));
        $manager->persist($briefValid);
        $manager->flush();
    }

    public function getDependencies()
    {
        return array(
            StatusFixtures::class,
        );
    }
}

И я загружаю приборы таким образом в своих тестах

private $entityManager;

    protected function setUp()
    {
        $kernel = self::bootKernel();

        $this->entityManager = $kernel->getContainer()
            ->get('doctrine')
            ->getManager();

        $status = new StatusFixtures();
        $status->load($this->entityManager);

        $fixture = new BriefFixtures();
        $fixture->load($this->entityManager);
    }

И моя ошибка Error: Call to a member function addReference() on null

$this из StatusFixtures кажется нулевой, но я непонять, почему это правильно работает, когда я загружаю приборы, а не когда я запускаю свои тесты.

Может быть, что-то отсутствует в setUp ()?

Спасибо за помощь

1 Ответ

1 голос
/ 26 октября 2019

Проблема заключается в документации Symfony для приборов . Это заставляет вас чувствовать, что $fixture->load($this->entityManager); просто загрузит прибор, но это не так. Это просто, когда вы используете команду doctrine:fixtures:load, потому что она делает больше, чем просто вызов функции загрузки.

Переход от сторонних решений будет самым быстрым и, вероятно, лучшим решением. Вот несколько библиотек, которые вы можете использовать:

  1. liip / LiipTestFixturesBundle
  2. hautelook / AliceBundle (спасибо michal)

Ошибка, которую вы получаете, исходит от ReferenceRepository объекта, который должен хранить ссылки, но имеет значение null. Кто на самом деле устанавливает этот репозиторий, так это Doctrine\Common\DataFixtures\Executor\AbstractExecutor.. Вам нужен загрузчик, который загружает прибор, создавая все необходимое для его работы. Один из этих загрузчиков - Doctrine\Bundle\FixturesBundle\Loader\SymfonyFixturesLoader, используемый вашей командой doctrine:fixtures:load. Вы можете использовать этот загрузчик или написать свой собственный загрузчик. Вы можете увидеть , что этот загрузчик должен сделать, чтобы предоставить вам ожидаемые результаты. Но это все же не так, вам также нужно Doctrine\Common\DataFixtures\Executor\ORMExecutor, потому что ваш Fixture является объектом базы данных, и вам нужно его сохранить. Вы можете видеть, как doctrine:fixtures:load использует SymfonyFixturesLoader и ORMExecutor для обеспечения ожидаемого результата. Таким образом, вам придется написать собственное решение для этого. Я раньше работал с Loader, потому что не хотел использовать сторонние решения. Я ставлю это ниже. Это может не совсем соответствовать вашим целям, но даст вам идеи, как написать свой собственный загрузчик, если хотите.


namespace App\Tests\Extra;

use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\ORM\EntityManagerInterface;
use App\Tests\Extra\Exception\FixtureNotLoadedException;

class FixtureLoader
{
    private $entityManager;
    private $loader;
    private $registry;

    public function __construct(
        EntityManagerInterface $entityManager,
        ManagerRegistry $registry
    ) {
        $this->entityManager = $entityManager;
        $this->registry = $registry;
    }

    public function loadFixtures(array $classNames) : void
    {
        $this->loader = new Loader();

        foreach ($classNames as $className) {
            $this->loader->addFixture(new $className());
        }

        $executor = new ORMExecutor($this->entityManager, new ORMPurger());
        $executor->execute($this->loader->getFixtures());
    }

    public function getFixture(string $className) : Fixture
    {
        if ($this->loader == null) {
            throw new FixtureNotLoadedException(
                sprintf(
                    'The fixture %s must be loaded before you can access it.',
                    $className
                )
            );
        }

        return $this->loader->getFixture($className);
    }

    private function getPurger() : ORMPurger
    {
        $purger = new ORMPurger($this->entityManager);
        $purger->setPurgeMode(ORMPurger::PURGE_MODE_TRUNCATE);

        return $purger;
    }

    public function cleanDatabase() : void
    {
        $connection = $this->entityManager->getConnection();

        $mysql = ('ORM' === $this->registry->getName()
            && $connection->getDatabasePlatform() instanceof MySqlPlatform);
        if ($mysql) {
            $connection->query('SET FOREIGN_KEY_CHECKS=0');
        }
        $this->getPurger()->purge();
        if ($mysql) {
            $connection->query('SET FOREIGN_KEY_CHECKS=1');
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...