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?
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
In order to bypass user confirmation you can use
doctrine:fixtures:load --no-interaction
or
doctrine:fixtures:load -n
You can create a base class for your test cases which makes fixture loading easy by leveraging some classes from the Doctrine Data Fixtures library. This class would look pretty much 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, simply extend the above class and before your test add all the needed fixtures and execute them. This will automatically purge your database before loading fixtures. Example follows:
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!
}
}
(I decided to "deprecate" this answer because it only explains how to clean up the database without telling how to load fixtures after).
There's an even cleaner way of accomplishing this without having to run commands. It basically consists in using a combination of the SchemaTool and the ORMPurger. You can create an abstract base class which performs this kind of operations to avoid repeating them for each specialized test case. Here's a code example of a test case class which sets up database for a generic 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();
}
}
This way, before running each test case which inherits from the above class, the database schema will be rebuilt from scratch, then cleaned up after every test run.
Hope this helps.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With