Testing
To build better and more reliable applications, you should test your code using both functional and unit tests. First, read the Testing chapter on the Symfony2 documentation. It explains everything you need to know to write tests for your Symfony2 application. However, it doesn't explain how to configure Propel, or how to use it in your test classes.
This recipe introduces Propel in the wonderful testing world. If you are reading it, you are probably interested in functional tests as relying on a database means you write functional tests, not unit tests.
Symfony2 provides a
WebTestCase
which provides great features for your functional test classes. This is the
class you need when you want to do black box testing. Then again, this is
explained in the Testing chapter - Functional
tests.
Moreover, Symfony2 comes with multiple environments, like dev
, prod
but
also test
. The Symfony2 Client, detailled in the section Working with the
Test Client
in the Symfony2 documentation, relies on this test
environment.
The Test Environment
The config_test.yml
file is where you have to put specific configuration for
testing purpose. For example, you can setup a new database for your tests like
yourdatabase_test
:
# app/config/config_test.yml
propel:
dbal:
dsn: %database_driver%:host=%database_host%;dbname=%database_name%_test;charset=UTF8
You can also configure a SQLite
connection instead of your production database
vendor (MySQL
, PostgreSQL
, etc.). It's a good idea to use a different
database vendor to ensure your application is not tied to a specific database,
however sometimes it's not possible.
As you may know, Propel uses smart code generation depending on the database vendor, and so on. You need to build both SQL and PHP code before to run your tests. It's doable by running a single command line, but it's not optimal.
The Propel WebTestCase
A good idea is to extend the WebTestCase
class in your application, and to add
a few methods to run commands for you:
<?php
namespace Acme\DemoBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
class WebTestCase extends BaseWebTestCase
{
private static $application;
public static function setUpBeforeClass()
{
\Propel::disableInstancePooling();
self::runCommand('propel:build --insert-sql');
}
protected static function getApplication()
{
if (null === self::$application) {
$client = static::createClient();
self::$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($client->getKernel());
self::$application->setAutoExit(false);
}
return self::$application;
}
protected static function runCommand($command)
{
$command = sprintf('%s --quiet', $command);
return self::getApplication()->run(new \Symfony\Component\Console\Input\StringInput($command));
}
}
Basically, for each test class, it will build everthing before to execute test
methods. By using this class, you just need to run phpunit
in your project to
run all tests, including functional tests that rely on a database. In other
words, it's setup your application in test
environment, just like you would do
in production.
<?php
namespace Acme\DemoBundle\Tests\Controller;
class DefaultControllerTest extends WebTestCase
{
// Your tests
}
You can run more commands, like the propel:fixtures:load
command. It's up to
you. You now have all keys to automatically run functional tests with Propel
inside.
<?php
self::runCommand('propel:fixtures:load @AcmeDemoBundle --yml');
If you want to write unit tests for your Model classes for some reasons, you can
follow the same principle in your own TestCase
class.
The Propel TestCase
If you don't use the Symfony2 Client, you don't need to extend the WebTestCase
class, just write your own TestCase
class:
<?php
namespace Acme\DemoBundle\Tests;
require_once __DIR__ . '/../../../../app/AppKernel.php';
class TestCase extends \PHPUnit_Framework_TestCase
{
private static $application;
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
if (null === self::$application) {
self::runCommand('propel:build --insert-sql');
}
}
protected static function getApplication()
{
if (null === self::$application) {
$kernel = new \AppKernel('test', true);
$kernel->boot();
self::$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
self::$application->setAutoExit(false);
}
return self::$application;
}
protected static function runCommand($command)
{
$command = sprintf('%s --quiet', $command);
return self::getApplication()->run(new \Symfony\Component\Console\Input\StringInput($command));
}
}
Having both WebTestCase
and TestCase
classes allow you to write Propel aware
tests in your application. You don't need anything else. You can read the PHPUnit
documentation for more information on
assertions.
Travis-CIĀ
Once you have a decent test suite, you may want to use Travis-CI. Here is a standard configuration for Symfony2 projects:
language: php
php:
- 5.3
- 5.4
before_script:
- curl -s http://getcomposer.org/installer | php -- --quiet
- php composer.phar install
- php app/console propel:database:create --env=test
script: phpunit
Found a typo ? Something is wrong in this documentation ? Just fork and edit it !