Best way to create a test database and load fixtur

2019-01-13 04:12发布

I have a WebTestCase that executes some basic routes in my application.

I want to, on the setUp method of PHPUnit, create a test database identical to my main database, and load fixtures into it.

I'm currently doing some workaround and executing some console commands, something like this:

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;
    }
}

But I'm quite sure this is not the best approach, especially because the doctrine:fixtures:load expects the user to hit a Y char to confirm the action.

How can I solve that?

7条回答
爷、活的狠高调
2楼-- · 2019-01-13 04:26

Just recently the bundle hautelook/AliceBundle expose two traits to help you solve the use case of loading fixtures in functional tests: RefreshDatabaseTrait and ReloadDatabaseTrait.

From the doc:

namespace App\Tests;

use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class NewsTest extends WebTestCase
{
    use RefreshDatabaseTrait;

    public function postCommentTest()
    {
        $client = static::createClient(); // The transaction starts just after the boot of the Symfony kernel
        $crawler = $client->request('GET', '/my-news');
        $form = $crawler->filter('#post-comment')->form(['new-comment' => 'Symfony is so cool!']);
        $client->submit($form);
        // At the end of this test, the transaction will be rolled back (even if the test fails)
    }
}

And you are good !

查看更多
Summer. ? 凉城
3楼-- · 2019-01-13 04:29

I used this command:

yes | php app/console doctrine:fixtures:load --purge-with-truncate

But of course LiipFunctionalTestBundle looks promising.

查看更多
冷血范
4楼-- · 2019-01-13 04:30

If you want to use doctrine:fixtures:load, you can use the --append option to avoid the user confirmation. Since you are recreating the database every time, purging is unnecessary. I used to use doctrine fixtures alone for testing, but have since switched to using fixtures & LiipFunctionalTestBundle to avoid DRY. This bundle makes fixtures easier to manage.

EDIT: David Jacquel's answer is the correct one for loading Doctrine Fixtures:

doctrine:fixtures:load --no-interaction 
or
doctrine:fixtures:load -n
查看更多
看我几分像从前
5楼-- · 2019-01-13 04:32

I wanted to load all your fixtures like the doctrine:fixtures:load command does. I didn't want to run exec from inside the test case because it seemed like a messy way to do things. I looked at how the doctrine command does this itself and just copied over the relevant lines.

I extended from the Symfony WebTestCase and after the Kernel was created I just called my method which works exactly like the Doctrine load-fixtures command.

    /**
     * Load fixtures for all bundles
     *
     * @param Kernel $kernel
     */
    private static function loadFixtures(Kernel $kernel)
    {
        $loader = new DataFixturesLoader($kernel->getContainer());
        $em = $kernel->getContainer()->get('doctrine')->getManager();

        foreach ($kernel->getBundles() as $bundle) {
            $path = $bundle->getPath().'/DataFixtures/ORM';

            if (is_dir($path)) {
                $loader->loadFromDirectory($path);
            }
        }

        $fixtures = $loader->getFixtures();
        if (!$fixtures) {
            throw new InvalidArgumentException('Could not find any fixtures to load in');
        }
        $purger = new ORMPurger($em);
        $executor = new ORMExecutor($em, $purger);
        $executor->execute($fixtures, true);
    }
查看更多
男人必须洒脱
6楼-- · 2019-01-13 04:40

I've stumbled upon a really neat bundle named Doctrine-Test-Bundle Instead of creating and dropping schema on every test it simply rollback. My Tests went from 1m40s to.. 2s. And it's isolated. All you need is a clear test database and it'll do the trick.

查看更多
啃猪蹄的小仙女
7楼-- · 2019-01-13 04:50

In order to bypass user confirmation you can use

doctrine:fixtures:load --no-interaction
or
doctrine:fixtures:load -n
查看更多
登录 后发表回答