在Symfony 2 WebTestCase上创建测试数据库和加载fixture的最佳方法是什么?

Dan*_*iro 64 tdd doctrine symfony

我有一个WebTestCase,它在我的应用程序中执行一些基本路由.

我想,在setUpPHPUnit 的方法中,创建一个与我的主数据库相同的测试数据库,并将fixture加载到其中.

我正在做一些解决方法并执行一些控制台命令,如下所示:

class FixturesWebTestCase extends WebTestCase
{
    protected static $application;

    protected function setUp()
    {
        self::runCommand('doctrine:database:create');
        self::runCommand('doctrine:schema:update --force');
        self::runCommand('doctrine:fixtures:load --purge-with-truncate');
    }

    protected static function runCommand($command)
    {
        $command = sprintf('%s --quiet', $command);

        return self::getApplication()->run(new StringInput($command));
    }

    protected static function getApplication()
    {
        if (null === self::$application) {
            $client = static::createClient();

            self::$application = new Application($client->getKernel());
            self::$application->setAutoExit(false);
        }

        return self::$application;
    }
}
Run Code Online (Sandbox Code Playgroud)

但我很确定这不是最好的方法,特别是因为doctrine:fixtures:load期望用户点击一个Y字符来确认操作.

我怎么解决这个问题?

Dav*_*uel 35

为了绕过用户确认,您可以使用

doctrine:fixtures:load --no-interaction
or
doctrine:fixtures:load -n
Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 34

如果要使用doctrine:fixtures:load,可以使用该--append选项来避免用户确认.由于每次都在重新创建数据库,因此不需要进行清除.我曾经单独使用doctrine fixtures进行测试,但后来改用了fixture和LiipFunctionalTestBundle来避免DRY.该捆绑包使夹具更易于管理.

编辑:David Jacquel的答案是加载Doctrine Fixtures的正确答案:

doctrine:fixtures:load --no-interaction 
or
doctrine:fixtures:load -n
Run Code Online (Sandbox Code Playgroud)

  • "镇上的新捆绑"似乎有点夸大其词.该问题已有2年,捆绑包本身在10个月内未更新.不是说Liip最近也有更新. (2认同)

And*_*ega 33

更新的答案

您可以为测试用例创建一个基类,通过利用Doctrine Data Fixtures库中的某些类,可以轻松地加载夹具.这个类看起来很像这样:

<?php

use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

abstract class FixtureAwareTestCase extends KernelTestCase
{
    /**
     * @var ORMExecutor
     */
    private $fixtureExecutor;

    /**
     * @var ContainerAwareLoader
     */
    private $fixtureLoader;

    public function setUp()
    {
        self::bootKernel();
    }

    /**
     * Adds a new fixture to be loaded.
     *
     * @param FixtureInterface $fixture
     */
    protected function addFixture(FixtureInterface $fixture)
    {
        $this->getFixtureLoader()->addFixture($fixture);
    }

    /**
     * Executes all the fixtures that have been loaded so far.
     */
    protected function executeFixtures()
    {
        $this->getFixtureExecutor()->execute($this->getFixtureLoader()->getFixtures());
    }

    /**
     * @return ORMExecutor
     */
    private function getFixtureExecutor()
    {
        if (!$this->fixtureExecutor) {
            /** @var \Doctrine\ORM\EntityManager $entityManager */
            $entityManager = self::$kernel->getContainer()->get('doctrine')->getManager();
            $this->fixtureExecutor = new ORMExecutor($entityManager, new ORMPurger($entityManager));
        }
        return $this->fixtureExecutor;
    }

    /**
     * @return ContainerAwareLoader
     */
    private function getFixtureLoader()
    {
        if (!$this->fixtureLoader) {
            $this->fixtureLoader = new ContainerAwareLoader(self::$kernel->getContainer());
        }
        return $this->fixtureLoader;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的测试用例中,只需扩展上面的类,然后在测试之前添加所有需要的fixture并执行它们.这将在加载灯具之前自动清除数据库.示例如下:

class MyTestCase extends FixtureAwareTestCase
{
    public function setUp()
    {
        parent::setUp();

        // Base fixture for all tests
        $this->addFixture(new FirstFixture());
        $this->addFixture(new SecondFixture());
        $this->executeFixtures();

        // Fixtures are now loaded in a clean DB. Yay!
    }
}
Run Code Online (Sandbox Code Playgroud)

老答复

(我决定"弃用"这个答案,因为它只解释了如何清理数据库而不告诉如何加载夹具).

有一个更简洁的方法来实现这一点,而无需运行命令.它基本上包括使用SchemaTool和ORMPurger的组合.您可以创建一个抽象基类来执行此类操作,以避免为每个专门的测试用例重复它们.下面是一个测试用例类的代码示例,它为通用测试用例设置数据库:

use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\Tools\SchemaTool;

abstract class DatabaseAwareWebTestCase extends WebTestCase {

    public static function setUpBeforeClass() {

        parent::setUpBeforeClass();

        $kernel = static::createKernel();
        $kernel->boot();
        $em = $kernel->getContainer()->get('doctrine')->getManager();
        $schemaTool = new SchemaTool($em);
        $metadata = $em->getMetadataFactory()->getAllMetadata();

        // Drop and recreate tables for all entities
        $schemaTool->dropSchema($metadata);
        $schemaTool->createSchema($metadata);
    }

    protected function tearDown() {

        parent::tearDown();

        $purger = new ORMPurger($this->getContainer()->get('doctrine')->getManager());
        $purger->setPurgeMode(ORMPurger::PURGE_MODE_TRUNCATE);
        $purger->purge();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,在运行继承自上述类的每个测试用例之前,将从头开始重建数据库模式,然后在每次测试运行后进行清理.

希望这可以帮助.


Des*_*ium 5

我偶然发现了一个名为Doctrine-Test-Bundle的非常简洁的软件包, 而不是在每个测试中创建和删除模式,而只是简单地回滚.我的测试从1分40秒到2分钟.它是孤立的.您所需要的只是一个清晰的测试数据库,它可以解决问题.