Willem
Willem Luijt
Lead Developer
Software Architect / Testing Specialist
Blog

Automatically Test with PHPUnit

Testing with PHPUnit is great! It allows a developer to rest assured that the logic they coded months ago still works. But when a project is being worked on by multiple developers, each developer may have different needs when it comes to testing. Luckily, PHPUnit allows a developer to create and use a phpunit.xml configuration file.

The phpunit.xml file is read by PHPUnit if the file exists and sets the configuration of the test environment based on its contents. A developer can place the phpunit.xml file at the root of a project directory so that the configuration can be read automatically. Most developers who practice Test Driven Development (TDD) would want to create unit and functional tests. The phpunit.xml file can be configured to execute all of the unit and functional tests with something like the following:

<?xml version="1.0" encoding="UTF-8"?>  
<phpunit>  
    <testsuites>  
        <testsuite name="Unit Tests">  
            <directory>test/phpunit/unit/</directory>  
        </testsuite>  
        <testsuite name="Functional Tests">  
            <directory>test/phpunit/functional/</directory>  
        </testsuite>  
    </testsuites>  
</phpunit>

When this phpunit.xml file exists, executing all of the tests is really simple as it only requires the following command:
phpunit

Without the phpunit.xml file, the command would look more like this:
phpunit test/phpunit

Sure, the second command above is not so difficult to remember. But, the phpunit.xml file really shines when you have a number of additional configuration options set, like this:

<?xml version="1.0" encoding="UTF-8"?>  
<phpunit backupGlobals="false"  
         backupStaticAttributes="false"  
         colors="true"  
         convertErrorsToExceptions="true"  
         convertNoticesToExceptions="true"  
         convertWarningsToExceptions="true"  
         processIsolation="true"  
         stopOnFailure="true"  
         syntaxCheck="false"  
>  
    <testsuites>  
        <testsuite name="Unit Tests">  
            <directory>test/phpunit/unit/</directory>  
        </testsuite>  
        <testsuite name="Functional Tests">  
            <directory>test/phpunit/functional/</directory>  
        </testsuite>  
    </testsuites>  
</phpunit>

With this phpunit.xml file, executing all of the tests still uses the same command:
phpunit

Without the phpunit.xml file, the command gets even more complicated:
phpunit --colors --process-isolation --stop-on-failure test/phpunit

Since testing is supposed to be something that happens often with TDD, having a simple one word command helps speed up the process tremendously.

Now, if there are multiple developers on a project, each one may only have a certain portion of the project that they need to test frequently. Those developers can each keep their own custom copy of the phpunit.xml file. For example, a developer who works with the database and the model layer of an MVC framework may only be interested in the results of the unit tests and could have a phpunit.xml file that looks like this:

<?xml version="1.0" encoding="UTF-8"?>  
<phpunit>  
    <testsuites>  
        <testsuite name="Unit Tests">  
            <directory>test/phpunit/unit/</directory>  
        </testsuite>  
    </testsuites>  
</phpunit>

Another great thing about PHPUnit is that you can create a phpunit.xml.dist file. The phpunit.xml.dist file can be included in a project's revision control repository (like Subversion or Git). The contents of the phpunit.xml.dist will be pretty much the same as the phpunit.xml file. Having a separate phpunit.xml.dist file allows a developer to create a local, custom phpunit.xml file if they want. PHPUnit will look for a phpunit.xml file first before looking for a phpunit.xml.dist file. This allows a project to have an even more complicated configuration that can be used with continuous integration servers, which execute tests automatically at specified intervals.
So, a project can have a phpunit.xml.dist file like the following:

<?xml version="1.0" encoding="UTF-8"?>  
<phpunit backupGlobals="false"  
         backupStaticAttributes="false"  
         bootstrap="./test/phpunit/bootstrap/phpunit.php"  
         colors="true"  
         convertErrorsToExceptions="true"  
         convertNoticesToExceptions="true"  
         convertWarningsToExceptions="true"  
         processIsolation="true"  
         stopOnFailure="false"  
         syntaxCheck="false"  
>  
    <testsuites>  
        <testsuite name="Unit Tests">  
            <directory>test/phpunit/unit/</directory>  
        </testsuite>  
        <testsuite name="Functional Tests">  
            <directory>test/phpunit/functional/</directory>  
        </testsuite>  
    </testsuites>  
    <filter>  
        <whitelist>  
            <file>./apps/frontend/config/frontendConfiguration.class.php</file>  
            <directory suffix=".php">./apps/frontend/lib</directory>  
            <directory suffix=".php">./apps/frontend/modules/*/actions</directory>  
            <directory suffix=".php">./apps/frontend/modules/*/lib</directory>  
            <directory suffix=".php">./config</directory>  
            <directory suffix=".php">./lib/filter</directory>  
            <directory suffix=".php">./lib/form</directory>  
            <directory suffix=".php">./lib/model</directory>  
            <exclude>  
                <directory>./lib/filter/base</directory>  
                <directory>./lib/form/base</directory>  
                <directory>./lib/model/map</directory>  
                <directory>./lib/model/om</directory>  
            </exclude>  
        </whitelist>  
    </filter>  
    <logging>  
        <log type="coverage-html" target="./build/report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70" />  
        <log type="coverage-clover" target="./build/coverage.xml" />  
        <log type="json" target="./build/logfile.json" />  
        <log type="tap" target="./build/logfile.tap" />  
        <log type="junit" target="./build/logfile.xml" logIncompleteSkipped="false" />  
        <log type="testdox-html" target="./build/testdox.html" />  
        <log type="testdox-text" target="./build/testdox.txt" />  
    </logging>  
</phpunit>

This file will have PHPUnit generate a number of reports about the test execution results (something that a continuous integration server should provide). Generating those reports can add a lot of time to the test execution, though, since it now has to keep track of everything that happens in memory. A single developer would not want to wait for that extra time, especially if they execute tests multiple times in one day. So, if that developer created a local phpunit.xml file like in the very first example, which did not have the logging or filters, then they wouldn't have to wait for reports to be generated.

For a developer, having the ability to create a phpunit.xml configuration file for PHPUnit definitely helps with day to day testing. It allows one to execute tests quickly and to keep each test execution session consistent while giving enough flexibility to change the configuration for multiple development environments.

Reference:
http://www.phpunit.de/manual/current/en/appendixes.configuration.html

Our Latest Tweets