![]() |
|
Snippets |
|
I've been using the following code to run all tests in all plugins and applications.
Create an file with this code like 'run-all-test.php' and execute it in command line 'php run-all-test.php'.
Take a look at SF_ROOT_DIR, set the correct path of your ROOT project.
<?php define( 'SF_ROOT_DIR', dirname(__FILE__).'/../../../..' ); include( SF_ROOT_DIR.'/config/config.php' ); require_once($sf_symfony_lib_dir.'/config/sfConfig.class.php'); require_once($sf_symfony_lib_dir.'/vendor/lime/lime.php'); require_once($sf_symfony_lib_dir.'/vendor/pake/pakeFinder.class.php'); $h = new lime_harness(new lime_output_color()); $h->base_dir = SF_ROOT_DIR; // unit tests app $h->register_glob( SF_ROOT_DIR.'/test/unit/*Test.php' ); $h->register_glob( SF_ROOT_DIR.'/test/unit/*/*Test.php' ); // functional tests app $h->register_glob( SF_ROOT_DIR.'/test/functional/*Test.php'); $h->register_glob( SF_ROOT_DIR.'/test/functional/*/*Test.php'); // unit tests plugin $h->register_glob( SF_ROOT_DIR.'/plugins/*Plugin/test/unit/*Test.php' ); $h->register_glob( SF_ROOT_DIR.'/plugins/*Plugin/test/unit/*/*Test.php' ); // functional tests plugin $h->register_glob( SF_ROOT_DIR.'/plugins/*Plugin/test/functional/*Test.php' ); $h->register_glob( SF_ROOT_DIR.'/plugins/*Plugin/test/functional/*/*Test.php' ); $h->run();
To use database connections defined in the databases.yml configuration file, you can use the following snippet:
// initialize database manager $databaseManager = new sfDatabaseManager(); $databaseManager->initialize();
I find boring to wait to run all the tests while I'm focusing on a single one or few ones. Thus I decided to hack pake simpletest task to accept test group selection.
1st step:
In your Pake tasks folder (eg.: /usr/share/pear/pake/tasks) edit the pakeSimpletestTask.class.php file
public static function call_simpletest($task, $type = 'text', $dirs = array(), $test_file = null)
and add this few lines replacing the single line 48
if (!$test_file) { $files = pakeFinder::type('file')->name('*Test.php')->in($test_dirs); } else { $files = pakeFinder::type('file')->name($test_file)->in($test_dirs); }
This way you are making your pake test task able to accept "hints" about which file to load in the test folder.
2nd step:
Open the sfPakeTest.php file in your symfony/tasks folder and do the following: Add
$test_file = null; if (count($args) > 1) { $test_file = $args[1]; }
at line 14, then change last line into
pakeSimpletestTask::call_simpletest($task, 'text', $dirs_to_test, $test_file);
That's all.
Now you can launch symfony test <app_name> <test_filename> and have this only executed with no loss of time. You can even use wildcards!!! For example: symfont test myportal *ValidatorTest.php It will execute all the tests named with that pattern in your test/myportal folder.
Super confortable testing at last! Test driven programming requires very flexible test groups approach and this could be a small contribution. Hope it helps. Bye!
Even though the book is quite good, the part in which unit testing is explained could use some better information. Especially the testing with a database connection (Propel in this case) needs some fixing.
Below you find an example unit test in which the database is accessed.
It tests a fictional class 'testClass' with the method 'load()'. That method accesses the database ... for which Propel needs to be running. The Symfony application that is loaded is called 'myapp';
if (!@constant('SF_APP')) { // Only load constants in not done before (group tests) define('SF_APP', 'myapp'); define('SF_ENVIRONMENT', 'dev'); define('SF_DEBUG', TRUE); } if (!@constant('SF_ROOT_DIR')) { // Only load constants in not done before (group tests) include(dirname(__FILE__).'/../bootstrap/unit.php'); } sfCore::initSimpleAutoload(array(SF_ROOT_DIR.'/lib/model' // DB model classes ,$sf_symfony_lib_dir // Symfony itself ,dirname(__FILE__).'/../../lib' // Location class to be tested ,dirname(__FILE__).'/../../apps/stageselect/lib' // Location myapp application ,SF_ROOT_DIR.'/plugins')); // Location plugins set_include_path($sf_symfony_lib_dir . '/vendor' . PATH_SEPARATOR . SF_ROOT_DIR . PATH_SEPARATOR . get_include_path()); /* * Start database connection and Symfony core */ sfCore::bootstrap($sf_symfony_lib_dir, $sf_symfony_data_dir); sfContext::getInstance(); Propel::setConfiguration(sfPropelDatabase::getConfiguration()); Propel::initialize(); /* * Test */ // Init $oTest = new lime_test(1, new lime_output_color()); // Print head $oTest->diag('testClass'); $oTest->diag('----'); // Does the method load() exist in class 'testClass' $oTest->can_ok('testClass', 'load', 'testClass has method load()');
A good amount of people have expressed interest in unit testing file uploads. sfTestBrowser does not currently support this but we can use sfWebBrowser instead, as follows (uploadTest.php, to be placed in your unit tests directory):
require_once(dirname(__FILE__).'/../bootstrap/unit.php'); require_once(dirname(__FILE__).'/../../plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php'); require_once(dirname(__FILE__).'/../../plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php'); require_once($sf_symfony_lib_dir.'/config/sfConfig.class.php'); require_once($sf_symfony_lib_dir.'/util/sfToolkit.class.php'); sfConfig::set('sf_data_dir', dirname(__FILE__).'/../../data'); $file = dirname(__FILE__).'/../fixtures/photos/maine01.jpg'; $invalid_file = dirname(__FILE__).'/../fixtures/photos/maine01.foo'; $t = new lime_test(2, new lime_output_color()); $b = new sfWebBrowser(); $b->post('http://mysite/upload', array( 'file' => $file )); $t->like($b->getResponseText(), '/has been uploaded/', 'file uploads successfully'); $b->post('/upload', array( 'file' => $invalid_file )); $t->like($b->getResponseText(), '/we only allow images/', 'unsupported mime types are not uploaded');
N.B. You must have curl installed for this to work.
<?php ?>
If you create a custom validator, you might want to test it by creating a unit test script.
This is a sample unit test script for testing validators.
test/unit/myFooBarValidatorTest.php
<?php $app='frontend'; // Necessary for fonctional boostrap include(dirname(__FILE__).'/../test/bootstrap/unit.php'); include(dirname(__FILE__).'/../test/bootstrap/functional.php'); require_once(dirname(__FILE__).'/../../lib/validator/myFooBarValidator.class.php'); $context = sfContext::getInstance(); $request = $context->getRequest(); $manager = new sfValidatorManager(); $manager->initialize($context); $validator = new myFooBarValidator(); $validator->initialize($context); // The values to validate. // You can make a second array with values // that are supposed to fail and do another // loop below. $values = Array('foo', 'bar'); $t = new lime_test(count($values) * 2, new lime_output_color()); $t->diag('myFooBarValidator()'); foreach ( $values as $value ) { // Re-initialize the validation entry // Without this, the first failure would // cause any additional validation to // be skipped $manager->registerName('myname', false); $manager->registerValidator('myname', $validator); $request->setParameter('myname', $value); $retval = $manager->execute(); $t->is($retval, true); $t->is($request->getErrors(), Array()); // We remove the error so that the next loop // does not carry the error. $request->removeError('myname'); }
We wanted to use a 'propel-insert-sql' in our acceptance tests suite to clear DB before every test reducing interferences. We all learned here http://www.symfony-project.com/snippets/snippet/16 how to call a Pake task from our PHP code. To get a quiet 'propel-insert-sql' task letting 'test' task be verbose and reporting test results we must add a method to the pakeTask class in pakeTask.class.php file:
public function setVerbose() { $this->verbose = false; }
and edit sfPakePropel.php file to make 'propel-insert-sql' task quiet:
function run_propel_insert_sql($task, $args) { $task->setVerbose(); _call_phing($task, 'insert-sql'); }
This way we have a lot quiter acceptance test suite and a clean DB whenever we want.