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.’
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
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');