A web developer's blog. PHP, MySQL, CakePHP, Zend Framework, Wordpress, Code Igniter, Django, Python, CSS, Javascript, jQuery, Knockout.js, and other web development topics.

How to Unit Test your Zend Framework Application

I am trying to learn Unit Testing using Zend Framework. I have set up a test application called LyZend in Github. Supposedly, the application should be able to display artists, albums, and tracks.

The tests are found in: http://github.com/wenbert/lyzend/tree/master/tests/ I have follwed Matthew Weier O’phinney’s method of setting up the tests.

lyzend / tests / TestHelper.php

<?php
require_once 'TestConfig.php';
 
/*
 * Start output buffering
 */
ob_start();
 
/*
 * Set error reporting to the level to which Zend Framework code must comply.
 */
error_reporting( E_ALL | E_STRICT );
 
/*
 * Set default timezone
 */
date_default_timezone_set('GMT');
 
/*
 * Determine the root, library, tests, and models directories
 */
$root        = realpath(dirname(__FILE__) . '/../');
$library     = $root . '/library';
$tests       = $root . '/tests';
$models      = $root . '/application/models';
$controllers = $root . '/application/controllers';
 
/*
 * Prepend the library/, tests/, and models/ directories to the
 * include_path. This allows the tests to run out of the box.
 */
$path = array(
    $models,
    $library,
    $tests,
    get_include_path()
    );
set_include_path(implode(PATH_SEPARATOR, $path));
 
/**
 * Register autoloader
 */
require_once 'Zend/Loader/Autoloader.php';
//Zend_Loader::registerAutoload();
Zend_Loader_Autoloader::getInstance();
 
/*
 * Add library/ and models/ directory to the PHPUnit code coverage
 * whitelist. This has the effect that only production code source files appear
 * in the code coverage report and that all production code source files, even
 * those that are not covered by a test yet, are processed.
 */
if (defined('TESTS_GENERATE_REPORT') && TESTS_GENERATE_REPORT === true &&
    version_compare(PHPUnit_Runner_Version::id(), '3.1.6', '>=')) {
    PHPUnit_Util_Filter::addDirectoryToWhitelist($library);
    PHPUnit_Util_Filter::addDirectoryToWhitelist($models);
    PHPUnit_Util_Filter::addDirectoryToWhitelist($controllers);
}
 
 
/**
 * Setup default DB adapter
 */
/*
$db = Zend_Db::factory('pdo_sqlite', array(
    'dbname' => $root . '/data/db/bugs.db',
));
Zend_Db_Table_Abstract::setDefaultAdapter($db);
*/
 
 
/*
 * Unset global variables that are no longer needed.
 */
unset($root, $library, $models, $controllers, $tests, $path);

You might noticed that I included a TestConfig.php file above. Here is the file:

<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
 
// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
 
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

Here is a sample test for my Artist Model.
lyzend / tests / application / models / ArtistTest.php

<?php
// Call Model_ArtistTest::main() if this source file is executed directly.
if (!defined("PHPUnit_MAIN_METHOD")) {
    define("PHPUnit_MAIN_METHOD", "Model_ArtistTest::main");
}
 
require_once dirname(__FILE__) . '/../../TestHelper.php';
 
/** Model_Artist */
require_once 'Artist.php';
require_once 'ArtistMapper.php';
require_once 'DbTable/Artist.php';
 
/**
 * Test class for Model_Artist.
 *
 * @group Models
 */
class Model_ArtistTest extends Zend_Test_PHPUnit_ControllerTestCase 
{
    /**
     * Runs the test methods of this class.
     *
     * @return void
     */
    public static function main()
    {
        $suite  = new PHPUnit_Framework_TestSuite("Model_ArtistTest");
        $result = PHPUnit_TextUI_TestRunner::run($suite);
    }
 
    /**
     * Sets up the fixture, for example, open a network connection.
     * This method is called before a test is executed.
     *
     * @return void
     */
 
    public function setUp()
    {
        $this->bootstrap = new Zend_Application(
            APPLICATION_ENV,
            APPLICATION_PATH . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR . 'application.ini'
        );
        parent::setUp();
 
    }
 
    /**
     * Tears down the fixture, for example, close a network connection.
     * This method is called after a test is executed.
     *
     * @return void
     */
    public function tearDown()
    {
    }
 
    public function testCanTest()
    {
        //this is a sample test
    }
}

The XML file is like this:

<phpunit>
    <testsuite name="Ly Test Suite">
        <directory>./</directory>
    </testsuite>
 
    <php>
        <!-- <ini name="include_path" value="../library"/> -->
    </php>
 
    <filter>
        <whitelist>
            <directory suffix=".php">../library/</directory>
            <directory suffix=".php">../application/</directory>
            <exclude>
                <directory suffix=".phtml">../application/</directory>
                <file>../application/Bootstrap.php</file>
                <file>../application/controllers/ErrorController.php</file>
            </exclude>
        </whitelist>
    </filter>
 
    <logging>
        <log type="coverage-html" target="./log/report" charset="UTF-8"
            yui="true" highlight="true"
            lowUpperBound="50" highLowerBound="80"/>
        <log type="testdox-html" target="./log/testdox.html" />
    </logging>
</phpunit>

Running the test would be something like this:

phpunit --configuration phpunit.xml

Matthew did not provide sample test for Mappers. So I created one something like this:

$mapper = new Ly_Model_ArtistMapper();
$this->assertTrue($mapper instanceof Ly_Model_ArtistMapper);

My process was like:

  1. Setup Unit Testing in Zend Framework
  2. Create tests (let’s say for Artist Model).
  3. Make code in my model to pass the tests.
  4. Repeat step 2 and then go to next model if satisfied.

FYI: I am not so sure about my Model. I am not sure if I am breaking any rules when I created them. It would be cool if you could check them out (http://github.com/wenbert/lyzend/tree/master/application/models/) and discuss my mistakes below.

Thanks!

This entry was posted in General and tagged , , . Bookmark the permalink.

5 Responses to How to Unit Test your Zend Framework Application

  1. Note that only [integration] tests which involves end-to-end request and controllers (typing an url, asserting that the html response is good) need to use Zend_Test. For testing of your models, mappers, services and so on you just need phpunit with the –bootstrap option. :)

  2. Thanks for the insight! There is a lot of helpful information within those links.Thanks for sharing..

    Website Designing

  3. Sarah Jones says:

    Thanks, this is very much helpful. Very informative.

  4. Kim says:

    Thanks, this pick’s up where Matthew’s leaves off. Very helpful.

  5. Frankie says:

    Hi.I am trying to create an app using zend framework but i can not seem to find out why my code will not move directories.
    can anyone please tell me because with this code :

    <?php

    defined('APPLICATION_ENVIRONMENT')
    || define('APPLICATION_ENVIRONMENT', (getenv('APPLICATION_ENVIRONMENT') ? getenv('APPLICATION_ENVIRONMENT') : 'development'));

    define('APP_ROOT', realpath(dirname(dirname(__FILE__))));

    set_include_path(implode(PATH_SEPARATOR, array(
    dirname(__FILE__) . '../library',
    get_include_path(),
    )));

    print_r(get_include_path());

    try
    {

    require '../application/Bootstrap.php';

    }
    catch(Exception $exception)

    {

    echo " an excpetion has occured during bootstrap”;
    echo getcwd();
    if (defined(APPLICATION_ENVIRONMENT) && APPLICATION_ENVIRONMENT !=’development’)
    {
    echo “” . $exception->getMessage() . “”
    .”" . $exception->getLine() . “”
    .”" . $exception->getFile() . “”
    .”Stack Trace;”
    .”

    " .$exception->getTraceAsString() . "

    “;
    }

    echo “”;
    exit(1);

    }

    //Zend_Controller_Front::getInstance()->dispatch();

    ?>

    i get this error in the browser:

    /Users/Neri/Sites/360/public../library:.:
    Warning: require(../application/Bootstrap.php) [function.require]: failed to open stream: No such file or directory in /Users/Neri/Sites/360/public/index.php on line 22

    Fatal error: require() [function.require]: Failed opening required ‘../application/Bootstrap.php’ (include_path=’/Users/Neri/Sites/360/public../library:.:’) in /Users/Neri/Sites/360/public/index.php on line 22″

    why why??????

Leave a Reply to Sarah Jones Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>