Symfony2: use a bootstrap file for your PHPUnit tests and run some console commands
Matthias Noback
One of the beautiful things about PHPUnit is the way it can be easily configured: for example you can alter the paths in which PHPUnit
will look for TestCase
classes. In your Symfony2 project this can be done in the file /app/phpunit.xml
(if it is called phpunit.xml.dist
, rename it to phpunit.xml
first!). This file contains a default configuration which suffices in most situations, but in case your TestCase classes are housed somewhere else than in your *Bundle/Test
, add an extra “directory” to the “testsuite” element in phpunit.xml
:
<phpunit>
<testsuites>
<testsuite name="Project Test Suite">
<!-- ... -->
<directory>../src/*/*Bundle/MoreTests</directory>
</testsuite>
</testsuites>
</phpunit>
I was looking for a way to run a console command right before any test was run. Looking through the configuration options for phpunit.xml, I found a way to run a “bootstrap” PHP file. You can point to this bootstrap file by setting the “bootstrap” of the root element in phpunit.xml
:
<phpunit bootstrap="my_phpunit_bootstrap.php">
The funny thing is, Symfony2 already uses this “bootstrap” attribute to load the most important files of the framework before the tests are run. So, when you want to provide your own bootstrap, make sure to include Symfony2’s bootstrap file first:
// in /app/my_phpunit_bootstrap.php:
require_once __DIR__.'/bootstrap.php.cache';
Let’s see if we can get some console commands to run from within this bootstrap file. For example, we might want to drop the test database and recreate it. We can accomplish this, by adding the following code to my_phpunit_bootstrap.php
.
But first set a different database name for the “test” environment. You can do this by adding these lines to /app/config/config_test.yml
:
doctrine:
dbal:
# add "_test" to the database name you set in parameters.ini:
dbname: %database_name%_test
Now, when you have a dedicated database for your test situation, put this in bootstrap.php
:
require_once __DIR__.'/bootstrap.php.cache';
require_once __DIR__.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
use Symfony\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
$kernel = new AppKernel('test', true); // create a "test" kernel
$kernel->boot();
$application = new Application($kernel);
// add the database:drop command to the application and run it
$command = new DropDatabaseDoctrineCommand();
$application->add($command);
$input = new ArrayInput(array(
'command' => 'doctrine:database:drop',
'--force' => true,
));
$command->run($input, new ConsoleOutput());
// add the database:create command to the application and run it
$command = new CreateDatabaseDoctrineCommand();
$application->add($command);
$input = new ArrayInput(array(
'command' => 'doctrine:database:create',
));
$command->run($input, new ConsoleOutput());
Of course, after dropping and creating the database, the last thing we need is to automatically create table. Add an extra use statement:
use Symfony\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand;
At the end of the file, add these lines:
// let Doctrine create the database schema (i.e. the tables)
$command = new CreateSchemaDoctrineCommand();
$application->add($command);
$input = new ArrayInput(array(
'command' => 'doctrine:schema:create',
));
$command->run($input, new ConsoleOutput());
Now we have a nice PHPUnit bootstrap that recreates the database and all tables on every test run.
Important addition
Please note: some problems occurred when using the solution described above. After quite some debugging, I found the solution (see my comment below).