phpunit-testingzend-frameworkphpunit

In a Zend framework 1 application, PHPUnit fails to load application.ini in Controllers but works in Models


We are using Zend framework 1.11.11. Our server has PHPUnit 3.7.9. We know that our version of Zend Framework doesn't support PHPUnit 3.7.9. But so far we have been able to use PHPUnit for testing models.

However, when it comes to testing controllers, PHPUnit fails. After placing dispatch() code in try/catch block, we learned that it was unable to load one property from Zend_Registry. It is defined application.ini. Same property is used in models and we have no issues there.

Is it possible that we are missing something? Or is it just not possible to use PHPUnit 3.7.9 with our version of ZF?

Here is phpunit.xml:

<phpunit bootstrap="./application/bootstrap.php" colors="true">
    <testsuite name="Precision Tests">
    <directory>./</directory>
</testsuite>

<filter>
    <whitelist>
        <directory suffix=".php">../application/</directory>
        <directory suffix=".php">../library/</directory>
        <exclude>
            <directory suffix=".phtml">../application/</directory>
            <directory>../library/Zend</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" hightlight="true"
        lowupperbound="50" highlowerbound="80">
        <log type="testdox" target="./log/testdox.html">
        </log>
    </log>
    </logging>
</phpunit>

The bootstrap.php in test:

<?php

function load($name) {
    $paths = array(
        "../application/controllers",
        "../library",
        "../application/models"
    );
    foreach($paths as $dir) {
        $name = str_replace("_", "/", $name);
        if(file_exists($dir."/".$name.".php")) {
            require_once($dir."/".$name.".php");
            break;
        }
    }
}

error_reporting(E_ALL | E_STRICT);

// 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') : 'development'));
$_SERVER["APPLICATION_ENV"] = getenv('APPLICATION_ENV');
$_SERVER["APPLICATION_ENV"] = 'development';

set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    realpath(APPLICATION_PATH . '/controllers'),
    get_include_path(),
)));

require_once 'Zend/Application.php';
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);

//setting up env variables:
$_SERVER["REMOTE_ADDR"] = '0.0.0.0';
$_SERVER['SERVER_NAME'] ='PHP.UNIT.TEST';
$_SERVER['REQUEST_URI'] = 'PHPUNITTEST';
$_SERVER['QUERY_STRING'] = 'PHPUNITTEST';

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('VP');
$autoloader->pushAutoloader("load");
spl_autoload_register();

require_once 'ControllerTestCase.php';

Then here is ControllerTestCase.php. Our models also extend same ControllerTestCase:

<?php

require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';

class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{
    /**
    * @var Zend_Application
    */
    protected $application;

    public function setUp() {
        $this->bootstrap = array($this, 'appBootstrap');
        parent::setUp();
    }

    public function appBootstrap() {
        $this->application = new Zend_Application(APPLICATION_ENV,
            APPLICATION_PATH . '/configs/application.ini');
        $this->application->bootstrap();
    }
}

And here is an example controller that doesn't load properties from application.ini:

<?php

class MyControllerTest extends ControllerTestCase
{
    public function setUp()
    {
        $this->getFrontController()->setControllerDirectory(APPLICATION_PATH . '/controllers');
        Zend_Controller_Action_HelperBroker::addHelper(new Zend_Layout_Controller_Action_Helper_Layout);
    }


    public function testSubscriptionStatus()
    {
        try{
            $this->dispatch('/my/subscriptionstatus');
            $this->assertController('my');
            $this->assertAction('subscriptionstatus');

        } catch (Exception $e) {
            print_r($e->getTrace());
        }
    }
}

And here how we setup our test models:

<?php

class Model_CustomerTest extends ControllerTestCase
{
    public function testDoSearch(){
        $x = Customer::doSearch('s');
        $this->assertTrue(count($x) > 0);
    }

}

And finally here is offending code that works in models but not in controllers (when running PHPUnit):

$registry = Zend_Registry::getInstance();
$options = $registry->webservices['logging'];

We have setup our PHPUnit testing environment by reading several different resources on the web. None of us are PHPUnit experts. So we just don't know what is going on.

Thank you!


Solution

  • The documentation isn't very clear on this but I think the controller test case class shouldn't actually do the bootstrapping, as PHPUnit needs to be able to do this before each test. At least this is how I have my controller base class (which works) setup. So try changing your setup method just to this:

    public function setUp() {
        $this->bootstrap = new Zend_Application(APPLICATION_ENV,
            APPLICATION_PATH . '/configs/application.ini');
        parent::setUp();
    }