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: Scripted Test

  • submit to reddit

Scripted Test is the main classes of tests that are written nowadays: a reproduction of hypothetical client code, that asserts the called code works correctly.

Scripted Tests enable us to use Test-Driven Development, and transform tests in an instrument of design instead of a mere checklist.

The Scripted Test approach gives tests the same dignity of the production code: we write and refactor them as they were ordinary classes. In PHPUnit, which is the standard testing automation framework for PHP applications, they are always represented as classes, but also as files in other testing frameworks. Unless differently specified, we will always refer to PHPUnit..

By the way, Recorded Tests introduced in the previous article cannot bypass under the user interface hood. Test for groups of objects (cmmonly named functional tests) or single classes (unit tests) have to be written by hand in some way. This is not necessarily an issue, since we probably want to write them in advance to ensure the production code they exercise will be testable and well decoupled from the rest of the application. Focusing on the client's point of view is the best way to start designing an Api, being it a web service or the set of public methods of a single object.

Many years ago Scripted Tests were, as the name suggest, standalone scripts (especially in PHP, which is in turn tested with phpt, a basic testing framework), that exercised the code under test and raised visible warnings in case of failures. Now we can write them with a testing automation framework which provides us automatic isolation and results processing, along with small libraries for asserting and mocking.

This is an example of plain old test script.

require_once 'Sum.php';

$sum = new Sum(23, 42);
$result = $sum->getValue();
if ($result !== 65) {
    throw new Exception('Sum produces an incorrect result.');
echo "Sum is ok.\n";

Note how likely repeating the various if-exception combination and messages between the various tests would be. Also aggregating the output of several of this script is not going to be easy.

This is how phpt, the tool used for testing PHP itself, would approach the problem:

Sum class test
require_once 'Sum.php';

$sum = new Sum(23, 42);
$result = $sum->getValue();

phpt compares the ouput of the --FILE-- section execution with the --EXPECT-- section. PHP native functions are tested with lots of scripts like this, which are the first step towards the definition of independent Test Cases.

Here's how PHPUnit defines a Scripted Test instead:

require_once 'Sum.php';

class SumTest extends PHPUnit_Framework_TestCase
    public function testProducesCorrectResult()
        $sum = new Sum(23, 42);
        $result = $sum->getValue();
        $this->assertSame(65, $result);

The PHPUnit's executable (/usr/bin/phpunit when installed via PEAR) will happily take the file, instance the test case one time for each test method to run, and tell you how many assertion failed. PHPUnit cannot be used to test the php interpreter or its own core, however, because a regression would affect also the testing harness.

The solutions available for testing have evolved over the years, and now you don't have to resort to manually run scripts anymore. PHPUnit is the PHP version of the xUnit series of frameworks, and provide you with all you need to set up a sandbox for your tests and running them, gathering statistics and displaying failures in the format you choose.

Before diving into how to write test code, we'll see a couple more general patterns, such as the Data-Driven test.

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.)


Mario T. replied on Mon, 2010/10/25 - 11:40am

Unit Tests are horrible. Not per se, mind you. But the PHPUnit API as it was copycated from Java makes little sense in PHP. While a bunch of assert functions and syntactic sugar are a necessity in Java, it's convoluting test systems in PHP where the extraneous fluff shouldn't be required.

It's imperative to recognize the semantic base of Unit tests. It's not an automated test system, as it requires spoon-feeding boolean results. The burden to define and/or assemble comparison data is on the user. Which it shouldn't be. PHPUnit only adds convolutedness and a script iterator. PHPT was a lot closer to separating testing code from testing data, but is likewise unautomated in requiring to assemble it manually.

PHPUnit is the defacto standard, but just look how this worked out for actual usage. So really I see a need for something significantly more appropriate on PHP. (Neither SimpleTest nor SnapTest are departuring from the JUnit bloat.)


Giorgio Sironi replied on Wed, 2010/10/27 - 2:39am in response to: Mario T.

There is really no alternative to PHPUnit today for PHP projects; for instance, Symfony has recently switched from Lime to PHPUnit itself. The problem with PHPT in my opinion, more than the manual assembling, is that I am forced to print results to make a confrontation.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.