Phing, PHPUnit and the Zend Framework

This article covers some of the issues I encountered trying to execute a unit test and create a coverage report using Phing. I was surprised at the number of patches and workarounds that I needed to get this to work, some being harder to track down than others.

My PHP environment had all the necessary prerequisites except PHPUnit. I installed PHPUnit to XAMPP as follows:


cd /opt/lampp/bin
sudo ./pear install phpunit/PHPUnit

This left me with the following PHP environment:

I created a simple controller unit test IndexControllerTest.php as follows:


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

    public function appBootstrap()
    {
        $controller = $this->getFrontController();
        $controller->registerPlugin(new OpenEprs_Controller_Plugin_Initialize('test'));
    }
    
    public function testIndexAction()
    {
        $this->dispatch ('/index/index');
        $this->assertController ('index');
        $this->assertAction ('index');
    }
}

I am leaving the details of setting up tests for a Zend Framework project to the reader. The main goal of the article is fixing Phing issues that prevent properly configured tests in a Zend Framework project from executing. The next step was to add a unit test target to my project’s build.xml:


<target depends="clean-reports" name="test">
    
    <mkdir dir="${report.dir}">
    <mkdir dir="${test.report.dir}">
    
    <phpunit codecoverage="false" haltonerror="true" haltonfailure="true" printsummary="true">
        <batchtest>
            <fileset dir="${test.dir}">
                <include name="**/*Test.php">
            </fileset>
        </batchtest>
        <formatter outfile="logfile.xml" todir="${test.report.dir}" type="xml">
    </phpunit>
    
    <phpunitreport>
        <infile="${test.report.dir}/logfile.xml" styledir="${phpunit.styles.dir}"
            format="frames"
            todir="${test.report.dir}" />
    </phpunitreport>
</target>

Running the following:

/opt/lampp/bin/phing -f build.xml test

resulted in nothing, it was as if PHPUnit was not installed. After spending what seemed for hours googling for a solution, I ran across this ticket #273 on the Phing Trac site. I also found another defect ticket #291 that reported the fix for ticket #273 was not applied to the current version of Phing. I downloaded the latest version of PHPUnitTask.php from Phing’s SVN trunk and copied it over the existing version:


sudo cp PHPUnitTask.php /opt/lampp/lib/php/phing/tasks/ext/

Re-running the unit tests now resulted in PHP not being able to locate and auto-load the files/classes required by the unit tests. That was a mistake on my part as my old test code used AllTests.php to run the test suites and TestConfiguration.php to setup the include paths and the Zend_Loader. I will show how I solved this problem later using the <adhoc> task which solved a similar problem building the coverage database. In the meantime, I reworked the tests to run without AllTests.php. Running the test target now resulted in this lovely HTML unit test report:
Unit Test Results
To get coverage reports on my tests, I started by modifying my previous test target in build.xml as follows:


<target depends="clean-reports" name="test">
    
    <mkdir dir="${report.dir}">
    <mkdir dir="${coverage.report.dir}">
    <mkdir dir="${test.report.dir}">
    
    <coverage-setup database="${coverage.report.dir}/coverage.db">
        <fileset dir="${app.dir}">
            <include name="**/*.php">
        </include></fileset>
        <fileset dir="${lib.dir}">
            <include name="**/*.php">
        </include></fileset>
    </coverage-setup>
    
    <phpunit codecoverage="true" haltonerror="true" haltonfailure="true" printsummary="true">
        <batchtest>
            <fileset dir="${test.dir}">
                <include name="**/*Test.php">
            </include></fileset>
        </batchtest>
        <formatter outfile="logfile.xml" todir="${test.report.dir}" type="xml">
    </phpunit>
    
    <phpunitreport infile="${test.report.dir}/logfile.xml" styledir="${phpunit.styles.dir}"
            format="frames"
            todir="${test.report.dir}" />
    
    <coverage-report outfile="${coverage.report.dir}/coverage.xml">
        <report styledir="${phpunit.styles.dir}" todir="${coverage.report.dir}"/>
    </coverage-report>
</target>

Running the tests resulted in the Phing <coverage-setup> task not being able to locate and auto-load the files/classes required to set up the coverage database. After spending another hour or two searching the web, I found a workaround that uses the <adhoc> task. This task can be used to setup the include path and Zend_Loader before calling the <coverage-setup> task. I went back to my build.xml and added the following before the <coverage-setup> task:

<adhoc>

This also allowed me to run my unit tests without using an external file to setup the PHP environment, in my case the TestConfiguration.php that I mentioned earlier. Running the test target resulted in everything working almost as expected producing this nice HTML coverage report:

Coverage Report
When I said “almost as expected”, there was still an error when running the tests:


[CoverageMerger.php]
[PHP Error] reset(): Passed variable is not an array or object [line 39 of /opt/lampp/lib/php/phing/tasks/ext/coverage/CoverageMerger.php]
[PHP Error] current(): Passed variable is not an array or object [line 41 of /opt/lampp/lib/php/phing/tasks/ext/coverage/CoverageMerger.php]
[PHP Error] current(): Passed variable is not an array or object [line 85 of /opt/lampp/lib/php/phing/tasks/ext/coverage/CoverageMerger.php]

This one was easy to track down on the Phing Trac site under ticket #263. This required me to edit CoverageMerger.php adding the following in function merge($project, $codeCoverageInformation) at line 115:


if (!is_array($right))
    $right = array_shift(PHPUnit_Util_CodeCoverage::bitStringToCodeCoverage(array($right), 1));

Whew! That was a lot of work get a PHPUnit test to execute with Phing. This is a huge contrast to my experience testing Ruby on Rails applications where everything just works. In all fairness, ROR is a monolithic stack where my PHP environment is built from many pieces that need a bit of massaging to get them to work together.

Please follow and like us:

One Reply to “Phing, PHPUnit and the Zend Framework”

Leave a Reply

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