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 !