Accessing Database in Unit Test with sfDoctrine

Whew! After made autoloading sfDoctrine available last week, I was thinking accessing database or pretending it (for test purpose) is surely easy. However, it wasn’t easy at all. So, here is the record of my struggle and, hopefully, if some knows (has) a better idea, or can point out my wrong, let me know it.

Here’s my idea. I am making a simple cashflow tracking app., so it has cashflow model and account model. If a user entered ‘Walmart’ as the paid account of the transaction, cashflow model would, first, search whether an account titled of ‘Walmart’ exists, and set the paid account id as the id of the account, if it exists. If no record titled of ‘Walmart’ were found, it would create a record titled of ‘Walmart’ and return the id of the record, and this id will be set as the account id of the cashflow. Unit test can validate this process by setting the account id of cashflow object with ‘Walmart’ and ‘Target’, while the account table has the record of only ‘Walmart.’

  1. So, first of all, I thought making a mock object that pretends as a doctrine record, and sfDoctrine has a Mock adapter. And since the Symfony book gave me an impression that propel objects can be filled with fixture data (Chapter 15. Unit and Functional Testing - Accessing Database), I thought it can be done with sfDoctrine as well. But making database connection using Mock adapter and filling the database with the fixture were not easy and I was able to make it after trace down to the Symfony and sfDoctrine execution chains and modification of the source code.

    • I wasn’t able to establish a Mock connection before made some changes in sfDoctrine code
    • I wasn’t able to fill the object with fixture data before made some changes in sfDoctrine code
    • I couldn’t use the filled data to query
  2. So I decided to have a test database. That will make things easier. One other problem that I had here was, if I load data from an array or a fixture, and query the database in the same file, it seems it couldn’t fetch the result. I still don’t know why, I’ll appreciate if anyone can give me a clear idea why. My workaround was putting the database manager initialization call prior to the database initialization.

    Here is my example unit test code. Hope this can help anyone desperate..

<?
include(dirname(__FILE__).'/../bootstrap/unit.php');
require_once($sf_symfony_lib_dir.'/util/sfCore.class.php');

define('SF_APP',         'track');
define('SF_ENVIRONMENT', 'test');
define('SF_DEBUG',       true);

sfCore::initSimpleAutoload(array(
    SF_ROOT_DIR."/lib/model",
    SF_ROOT_DIR."/apps/".SF_APP."/lib",
    SF_ROOT_DIR."/plugins/sfDoctrinePlugin",
    $sf_symfony_lib_dir,
));

require_once(SF_ROOT_DIR.'/apps/track/config/config.php');

$t = new lime_test(3, new lime_output_color());

$t->diag('cashflow test');
$t->is('Paid_account_id', ucfirst('paid_account_id'), 'filter method uses ucfirst function to transform fieldname');
$t->is('Payable_account_id', ucfirst('payable_account_id'), 'filter method uses ucfirst function to transform fieldname');


//
$t->diag('make database connection and fill the fixtures');

$manager = new sfDatabaseManager();
$manager->initialize();

$database = new sfDoctrineDatabase();
$database->initialize(array (
  'dsn' => 'mysql://root:root@localhost/symfony_cashflow_test',
), '');

$data = new sfDoctrineData();
$data->setDeleteCurrentData(true);
$fixtures = array(
  'Account' => array(
    '1' => array(
      'title' => 'Walmart',
    ),
  ),
);
$data->loadDataFromArray($fixtures);


//
$t->diag('test adding account when registering cashflow');

$cashflow = new Cashflow();
$cashflow->set('paid_account_id', 'Walmart');
$account = Doctrine_Query::create()->from('Account')->where('title = ?', 'Walmart')->limit(1)->execute()->getFirst();
$t->is($account->id, $cashflow->paid_account_id, 'set account with account title will set the value with account\'s id');

$t->diag('test end');

3 Responses to “Accessing Database in Unit Test with sfDoctrine”

  1. Jonathan Ding Says:

    Your article looks good. And I find the solution you want, as below. The major idea is that you should initialize the sfContext to get all dynamic stuff get created, while simple include the config.php to get all static settings correct.

  2. Jonathan Ding Says:

    Your article looks good. And I find the solution you want, as below. The major idea is that you should initialize the sfContext to get all dynamic stuff get created, while simple include the config.php to get all static settings correct.

    == the code == require_once(dirname(FILE).’/../bootstrap/unit.php’);

    define(’SF_ROOT_DIR’, realpath(dirname(FILE).’/..’)); define(’SF_APP’, ‘frontend’);

    // load the compiled Doctrine library require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.’lib’.DIRECTORY_SEPARATOR.’Doctrine.compiled.php’);

    // it will configure the system, including autoload require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.’apps’.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.’config’.DIRECTORY_SEPARATOR.’config.php’);

    // This initializes the context, it will initialize the database for you sfContext::getInstance();

    $t = new lime_test(1, new lime_output_color()) // your tests …

  3. Kaizenlog ยป Database 30/07/2007 Says:

    […] Accessing Database in Unit Test with sfDoctrine By sunhwan After made autoloading sfDoctrine available last week, I was thinking accessing database or pretending it (for test purpose) is surely easy. However, it wasn’t easy at all. So, here is the record of my struggle and, hopefully, … sunhwan - http://wp.omeeza.com/sunhwan […]

Leave a Reply