Best way to create a test database and upload fixtures to Symfony 2 WebTestCase?

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

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

I am currently doing some workarounds and running 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 sure this is not the best approach, especially because doctrine:fixtures:load expects the user to hit Y char to confirm the action.

How can i solve this?

+60
tdd symfony doctrine
Feb 07 '13 at 14:00
source share
7 answers

If you want to use doctrine:fixtures:load , you can use the --append option to avoid user confirmation. Because you recreate the database every time, no cleanup is needed. I used to use doctrine tools for testing, but have since switched to using lights and LiipFunctionalTestBundle to avoid DRY. This kit simplifies luminaire management.

EDIT: David Jaquel's answer is correct for downloading Doctrine appliances:

 doctrine:fixtures:load --no-interaction or doctrine:fixtures:load -n 
+33
Feb 07 '13 at 15:15
source share

To bypass user confirmation, you can use

 doctrine:fixtures:load --no-interaction or doctrine:fixtures:load -n 
+34
Oct. 15 '13 at 13:11
source share

UPDATED RESPONSE

You can create a base class for your test cases, which simplifies instrument loading using some classes from the Doctrine Data Fixtures library . This class will look something like this:

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

Then, in your test case, just add the class above and add all the necessary devices before the test and run them. This will automatically clear your database before loading fixtures. Example:

 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

(I decided to β€œtrick” this answer because it explains how to clear the database without specifying how to load the snap-ins after that).

There is an even cleaner way to accomplish this without having to run commands. This basically consists of using a combination of SchemaTool and ORMPurger. You can create an abstract base class that performs such operations in order to avoid repeating them for each specialized test case. Here is a sample test class code that sets up a database for a common test case:

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

Thus, before starting each test case that inherits from the above class, the database schema will be restored from scratch and then cleared after each test run.

Hope this helps.

+28
Mar 02 '14 at 19:53
source share

I came across a really neat package called Doctrine-Test-Bundle. Instead of creating and deleting a circuit with each test, this is just a rollback. My tests passed from 1m40 to .. 2s. And it is isolated. All you need is a clean test database and it will do the trick.

+5
Jun 13 '17 at 10:15
source share

I used this command:

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

But of course, the LiipFunctionalTestBundle looks promising.

+2
Nov 17 '13 at 5:55 on
source share

I wanted to load all your fixtures, as doctrine:fixtures:load does. I did not want to run exec from within the test case because it seemed like a messy way of doing something. I looked at how the doctrine command does this on its own and just copies along the appropriate lines.

I expanded from Symfony WebTestCase and after the kernel was created, I just called my method, which works exactly like the Load-fictures Doctrine 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); } 
0
Jun 21 '15 at 11:35
source share

More recently, the hautelook / AliceBundle package has revealed two features that will help you decide how to use instrument loading 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!

0
Dec 08 '18 at 13:02
source share



All Articles