我正在研究Symfony的项目,并且在用phpunit测试时遇到一些问题。
我有带有addReference
的StatusFixtures,可以在BriefFixtures中使用,并且当我执行doctrine:fixtures:load
时可以正常工作(正确依赖于在Brief之前加载Status)。
但是,当我使用这些灯具运行测试时,会出现以下错误:Error: Call to a member function addReference() on null
我的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();
}
}
我的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
似乎为空,但是我不明白为什么当我加载夹具时此方法可以正常工作,而当我运行测试时却不能再使用。
也许setUp()中缺少某些内容?
谢谢您的帮助
答案 0 :(得分:1)
问题出在Symfony documentation for Fixtures。它让你感觉像
$fixture->load($this->entityManager);
只会加载灯具,但事实并非如此。使用命令doctrine:fixtures:load
很简单,因为它不仅可以执行加载函数调用。
使用第三方解决方案将是最快,可能也是最好的解决方案。您可以使用以下几个库:
您遇到的错误来自应该存储引用的ReferenceRepository
对象,但它为null。谁真正建立了这个存储库,它是Doctrine\Common\DataFixtures\Executor\AbstractExecutor.
,您需要的是一个Loader,它通过创建其工作所需的所有内容来加载治具。这些加载程序之一是您的命令Doctrine\Bundle\FixturesBundle\Loader\SymfonyFixturesLoader
正在使用的doctrine:fixtures:load
。您可以使用该加载程序,也可以编写自己的加载程序。 You can see该加载程序必须执行的操作才能为您提供预期的结果。但这还不是,您还需要Doctrine\Common\DataFixtures\Executor\ORMExecutor
,因为Fixture是数据库实体,您需要对其进行持久化。 You can see that
how doctrine:fixtures:load
利用SymfonyFixturesLoader和ORMExecutor为您提供预期的结果。因此,您将必须为此编写自己的解决方案。我以前为自己设计了一个Loader,因为我不想使用第三方解决方案。我把它放在下面。它可能无法完全满足您的目的,但是如果您愿意,它将为您提供如何编写自己的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');
}
}
}