Category Archives: unit test

Generate phpunit fixtures

Last time I had a lot of work and that’s why can’t write something really interesting. So today I decided to write about another one zf command (read how do I do it here Run Zend Framework Command in Yii style) that helps me to build fixtures for PHPUnit.
Imagine you need to quickly create a fixture for some tables with many fields. Writing tests should not be time-consuming. So you do something like this

php script_runner.php createFixtureFromDb --table=user --print=1 --limit=1 --verbose

<?xml version="1.0" encoding="UTF-8"?>
<dataset><tags id="1" login="login" email="email@email.com" a lot of other fields etc.. />
</dataset>

Shortly how do I do that –

<?php

/**
 *
 * Creates fixture for testing from specified DB table
 * @author radzserg
 *
 */
class App_Script_Command_CreateFixtureFromDb extends App_Script_Command_Abstract
{

    protected $_availableParams = array(
        'table*' => 'Name of the table to import data',
        'file' => 'Path generated xml file. (Either file or print shoud be specified)',
        'print' => 'Output to stdout',
        'limit' => 'limit of rows',
        'rand' => 'if set will add order by RAND()',
    );

    public function execute($params = array())
    {
        if (empty($params['table'])) {
            throw new Exception("Specify source table");
        }
        if (empty($params['file']) && !isset($params['print'])) {
            throw new App_Exception_System("Specify file path for xml");
        }
        $limit = isset($params['limit']) ? (int)$params['limit'] : null;
        $cond = isset($params['cond']) ? $params['cond'] : null;
        $rand = isset($params['rand']) ? true : false;

        $table = $params['table'];
        $filePath = isset($params['file']) ? $params['file'] : null;

        /* @var $adapter Zend_Db_Adapter_Abstract */
        $adapter = Zend_Db_Table::getDefaultAdapter();
        $select = $adapter->select()->from($table);

        if ($rand) {
            $select->order(new Zend_Db_Expr('RAND()'));
        }
        $select->limit($limit);
        if ($cond) {
            $select->where($cond);
        }

        $rows = $adapter->fetchAll($select);

        $doc = new DomDocument('1.0', 'UTF-8');
        $root = $doc->createElement('dataset');
        $root = $doc->appendChild($root);

        foreach ($rows as $row) {
            $xmlRow = $doc->createElement($table);
            foreach ($row as $col => $value) {
                $xmlRow->setAttribute($col, $value);
            }

            $root->appendChild($xmlRow);
        }

        $xml = $doc->saveXML();

        if (!isset($params['print'])) {
            file_put_contents($filePath, $xml);
        } else {
            $this->verbose($xml, 'info');
        }
    }

}

As you can see from $_availableParams help variable we have to set required table param. Other params are optional. You can specify –limit for rows, –file – file path param if you want to save result to file, –print if you want to output result to console, and finally you can specify –rand variable if you want to randomize result.

That’s it, hope it was helpfull.

Unit tests for yii modules

Testing yii modules 

I was creating simple yii module (about which perhaps I will write later). Since last time I like TDD more and more I’ve decided to test it. But there is a problem I’d like to move all tests to [my_module]/tests and do not mix them with project tests.

I din’t find any good tutorial on this topic and decided to do it by myself.
Please note: I added only unit tests. But I believe it’s easy to add functional tests and you can do it by yourself. 

Ok let’s start first of all we create following test directory structure:

/config
— test.php
/tests
— /fixtures
— /unit
— bootstrap.php
— phpunit.xml

As you see this is the copy of standard yii directory structure except some files. In fixtures and unit folders we will put fixtures and tests files as we do for standard yii tests. phpunit.xml also will leave the same. Of course you can customize it as you need.

<phpunit bootstrap="bootstrap.php" colors="true" converterrorstoexceptions="true" convertnoticestoexceptions="true" convertwarningstoexceptions="true" stoponfailure="false">

    <testsuite name="all tests">
        <directory>./</directory>
    </testsuite>
</phpunit>

In bootstrap.php we will change paths and comment WebTestCase.php including

 $appPath = realpath(dirname(__FILE__) . '/../../../');
 $config = $appPath . '/modules/pct/config/test.php';
 require_once($appPath . '/yii/framework/yiit.php');
 //require_once(dirname(__FILE__).'/WebTestCase.php');
 Yii::createWebApplication($config);

And finally config.php

 $basePath = realpath(dirname(__FILE__) . '/../../..');

 return array(
     'basePath' => $basePath,

      'import' => array(
         'application.modules.[my_module].models.*',
         'application.modules.[my_module].components.*',
        // any other includings
     ),

     'components'=>array(
         'fixture'=>array(
             'class'=>'system.test.CDbFixtureManager',
             'basePath' => realpath(dirname(__FILE__) . '/../tests/fixtures'),
             // redefine basePath for module tests
         ),
         'db'=>array(
             'connectionString' => 'mysql:host=127.0.0.1;dbname=[test_db_name]',
             'username' => '',
             'password' => '',
         ),
     ),
 );

I define the whole config but you can use test config from main application by

return CMap::mergeArray(
 require(dirname(__FILE__).'../../../config/test.php'),
         array()

That’s it. Good testing for you guys and thank you.