Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

Practical PHP Testing Patterns: Test Runner

12.13.2010
| 6836 views |
  • submit to reddit

Tests are more PHP classes than PHP scripts, in the sense that they are not meant to be executed by themselves. Instead, they are classes which can be instantiated with the right parameters, often calculated using reflections over the class method names and annotations.

Once instantiated, the classes can be plugged in into PHPUnit and run. The Test Runner is the part of the framework which discovers, instantiates and run the various Testcases of your battery of tests.

In the case of PHPUnit, the PEAR installation places the main script at /usr/bin/phpunit: this file is a simple PHP script itself, which bootstraps PHPUnit.

Why there is a Test Runner?

The main purpose of the Test Runner is providing a place where to factor out the common logic which is handled by the test framework for you: gathering results, isolate the various tests, clean up memory and resources.

Gone are the days of require_once() statements at the top of test cases: the Test Runner of PHPUnit 3.x accepts a --bootstrap argument which should point to a script to execute once, before running the selected set of tests. The inclusion of this file is one of the facilities provided by the Test Runner, which saves you a lot of work which you would have to repeat on all your projects test suites.

A simple parallel can be made with web servers: the Test Runner provides a SPI at an higher level of abstraction, just like Apache and mod_php parse the HTTP request for you, so that your script can deal with predefined variables containing the parameters instead of a single request string.

Variations

Graphical Test runner: a graphic tool which helps you select the tests to run, and provides you the result in a window. We won't cover such tools here.

Command-Line Test Runner: the classic phpunit script, which the PEAR installation provides you with.

The power of the command line manifests itself also for Test Runner: a command-line one can easily be composed by other scripts. However, if the tools that interact with PHPUnit are PHP-based, you may want to interface directly with the PHP class that performs this work.

Phing for example provides tasks, like the <phpunit> phing element for build integration of the test suite, which have a preferred channel of communication with the Test Runner, different from the command line. In fact, the <phpunit> task creates PHPUnit objects directly, and the resulting channel is PHP-PHP instead of PHP-bash-PHP.

Examples

Here is an example of running phpunit with its Command-Line Test Runner:

[14:05:40][giorgio@Desmond:/var/www/NakedPhp]$ phpunit --colors --bootstrap tests/bootstrap.php tests/
PHPUnit 3.5.5 by Sebastian Bergmann.

............................................................ 60 / 251
...........................I...................I............ 120 / 251
................................................I........I.. 180 / 251
I.......................I................................... 240 / 251
...........

Time: 3 seconds, Memory: 21.75Mb

OK, but incomplete or skipped tests!
Tests: 251, Assertions: 471, Incomplete: 6.

We'll make some comments on the runner script instead of showing a test example, since the Runner is part of PHPUnit and you will never have to write one.

This is probably the /usr/bin/phpunit file on your system, or the file it links to. The #! shebang is a fake comment that tells Unix systems to execute this file with the indicated program instead of as a shell script.

#!/usr/bin/php
Since we have to execute it with PHP, we're better off opening the <?php tag to avoid accidental output, like we were in a plain old PHP script on a web server. Quality assurance tools for PHP applications are usually written in PHP, but use the command line as their interface, instead of producing HTML and responding to the HTTP request.
<?php
/* PHPUnit
*
* Copyright (c) 2002-2010, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
* [license cut...]
*/
This statement includes a file from the PHP_CodeCoverage PEAR component and tells it to not include this file into code coverage reports. PHPUnit won't disturb you with coverage over its own PHP files.
require_once 'PHP/CodeCoverage/Filter.php';
PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'PHPUNIT');

- The xdebug extension provides code coverage primitives when present.
if (extension_loaded('xdebug')) {
xdebug_disable();
}
Fixes the include path to include the directory this file is kept in.
if (strpos('/usr/bin/php', '@php_bin') === 0) {
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
}

require_once 'PHPUnit/Autoload.php';

define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main');

// starts the runner
PHPUnit_TextUI_Command::main();
As you can see, it's all good old PHP code. In fact, PHPUnit is partially tested with phpt because, being a PHP tool, a regression in it would case its own test suite to cease working.
Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)