Лучший способ создать тестовую базу данных и загрузить светильники на Symfony 2 WebTestCase?

У меня есть WebTestCase, который выполняет некоторые базовые маршруты в моем приложении.

Я хочу, в методе setUp PHPUnit, создать тестовую базу данных, идентичную моей основной базе данных, и загрузить в нее приборы.

В настоящее время я делаю обходное решение и выполняю некоторые команды консоли, что-то вроде этого:

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

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

Как я могу это решить?

56
См. Также мой ответ здесь: stackoverflow.com/questions/17091772/…
добавлено автор Marc Juchli, источник

6 ответы

Чтобы обойти пользовательское подтверждение, вы можете использовать

doctrine:fixtures:load --no-interaction
or
doctrine:fixtures:load -n
34
добавлено
Большое спасибо, я искал это, не повезло раньше.
добавлено автор Guillermo Gutiérrez, источник
на самом деле это лучший ответ, поскольку правильный способ это сделать.
добавлено автор GusDeCooL, источник

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.

РЕДАКТИРОВАТЬ: Ответ Дэвида Жакеля является правильным для загрузки приборов Doctrine:

doctrine:fixtures:load --no-interaction 
or
doctrine:fixtures:load -n
31
добавлено
Одна интересная вещь о LiipFunctionalTestBundle заключается в том, что вы можете использовать собственную тестовую базу данных, например Rails: github.com/liip/LiipFunctionalTestBundle # SQLite
добавлено автор webDEVILopers, источник
Но есть также дискуссия о «новом пакете в городе»: github.com/instaclick/ICBaseTestBundle/вопросы/24
добавлено автор webDEVILopers, источник
«новый пакет в городе» кажется немного завышенным. Эта проблема составляет 2 года, а сам комплект не обновляется через 10 месяцев. Не то, чтобы Лийп недавно был обновлен.
добавлено автор Mike, источник
Спасибо за отличный ответ и ссылку на LiipFunctionalTestBundle !
добавлено автор Daniel Ribeiro, источник

ОБНОВЛЕННЫЙ ОТВЕТ

Вы можете создать базовый класс для своих тестовых примеров, что упростит загрузку устройства, используя некоторые классы из 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;
    }
}

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

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

OLD ANSWER

(я решил «осудить» этот ответ, потому что он объясняет, как очистить базу данных, не указав, как после этого нужно загрузить приборы).

Есть еще более чистый способ выполнить это без необходимости запуска команд. В основном это состоит в использовании комбинации 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();
    }
}

Таким образом, перед запуском каждого тестового примера, который наследуется от вышеуказанного класса, схема базы данных будет восстановлена ​​с нуля, а затем очищена после каждого тестового прогона.

Надеюсь это поможет.

27
добавлено
@lazel звучит как laravel;)
добавлено автор Jaime Sangcap, источник
рекомендуется не очищать вашу базу данных в методе tearDown, если ваш тест завершился неудачно, вы все равно можете посмотреть в своей базе данных и проверить, что пошло не так
добавлено автор murtho, источник
Хороший ответ! Однако я бы предложил использовать черту вместо класса :)
добавлено автор Iazel, источник

Я наткнулся на действительно опрятный комплект, названный Doctrine-Test-Bundle Вместо того, чтобы создавать и отбрасывать схему на каждом тесте, он просто откатывается. Мои тесты прошли от 1м40 до 2. 2с. И это изолировано. Все, что вам нужно, это ясная тестовая база данных, и это поможет.

3
добавлено

Я использовал эту команду:

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

Но, конечно, LiipFunctionalTestBundle выглядит многообещающим.

2
добавлено

Я хотел загрузить все ваши приборы, как команда doctrine: fixtures: load . Я не хотел запускать exec из тестового примера, потому что он казался беспорядочным способом делать что-то. Я посмотрел, как команда доктрины делает это сама и просто копирует соответствующие строки.

Я расширился из Symfony WebTestCase , и после создания ядра я только что назвал свой метод, который работает точно так же, как и команда Doctrine load-fixtures.

    /**
     * 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);
    }
0
добавлено
symfony
symfony
1 045 участник(ов)

Сообщество Symfony, Symfony Components, Symfony Framework. Вакансии: https://t.me/symfony_careers Официальный slack: https://symfony.com/slack-invite

symfony
symfony
354 участник(ов)