Edit: Voir le commentaire de Bidule pour une solution plus simple
Il est très pratique d’isoler ses tests du reste de l’application. Il est donc nécessaire de faire en sorte que la base de donnée utilisé lors des tests soit indépendante de la base utilisé lors du développement. Cela évite de fausser ses tests si des données ont été modifier pendant le développement ainsi que d’utiliser une base fidèle aux fixtures entre chaque tests.
Cet article est issue de la combinaison des deux articles suivants:
- http://haulynjason.net/weblog/2012/01/fully-isolated-tests-in-symfony2/
- http://alexandre-salome.fr/blog/Symfony2-Isolation-Of-Tests
Dans mon cas, l’article de haulynjason.net seul ne me permettait pas d’exécuter mes tests fonctionnels sur la même base que les tests unitaires. J’ai du utiliser l’astuce de l’article d’alexamdre-salome.fr.
Premièrement nous configurons de quoi éxécuter les tests dans une base sqlite, de façon a ce qu’elle soit isolé de la base de développement.
config_test.yml:
dbal:
driver: pdo_sqlite
path: ":memory:"
memory: true
orm:
auto_generate_proxy_classes: true
auto_mapping: true
Nous créons la classe ModelTestCase a partir de laquelle seront étendus nos classes de tests (git):
$this->_kernel->boot();
$this->_container = $this->_kernel->getContainer();
parent::__construct();
}
protected function get($service)
{
return $this->_container->get($service);
}
public function setUp()
{
$this->_application = new \Symfony\Bundle\FrameworkBundle\Console\Application($this->_kernel);
$this->_application->setAutoExit(false);
$this->runConsole("doctrine:schema:drop", array("--force" => true));
$this->runConsole("doctrine:schema:create");
$this->runConsole("cache:warmup");
$this->runConsole("doctrine:fixtures:load");
}
protected function runConsole($command, Array $options = array())
{
$options["-e"] = "test";
$options["-q"] = null;
$options = array_merge($options, array('command' => $command));
return $this->_application->run(new \Symfony\Component\Console\Input\ArrayInput($options));
}
}
A partir d’ici vos classes de tests unitaires étendus de cette classes utiliserons la base sqlite pour exécuter ses tests. Passons maintenant aux tests fonctionnels: définissons le paramètre test.client.class afin d’écrire notre propre classe Client:
config.yml:
test.client.class: MyApp\CoreBundle\lib\Test\Client
$this->kernel->shutdown();
$this->kernel->boot();
}
$this->injectConnection();
$this->requested = true;
return $this->kernel->handle($request);
}
protected function injectConnection()
{
if (null === self::$connection) {
self::$connection = $this->getContainer()->get('doctrine.dbal.default_connection');
} else {
if (! $this->requested) {
self::$connection->rollback();
}
$this->getContainer()->set('doctrine.dbal.default_connection', self::$connection);
}
if (! $this->requested) {
self::$connection->beginTransaction();
}
}
}
Nous écrivons la classe WebTestCase a partir de laquelle nous étendrons nos classe de test fonctionnels:
$client->setServerParameters($server);
return $client;
}
}
Et voilà, nos tests fonctionnels seront étendu de WebTestCase, nos tests unitaires seront eux étendus de ModelTestCase et ils seront totalement isolé de la base de dév puisque ils travailleront avec une base indépendante. Les performances de vos tests seront affectés puisque avec cette méthode chaque test (fichier, pas fonction) effectue une rechargement de la base.


