Home arrow PHP arrow Unit Testing in Detail

Unit Testing in Detail

Last week, we introduced you to setting up a unit testing framework. This week, you will learn about running multiple tests simultaneously, creating more informative error messages, and more. This article, the second of three parts, is excerpted from chapter 6 of the book Advanced PHP Programming, written by George Schlossnagle (Sams; ISBN: 0672325616).

TABLE OF CONTENTS:
  1. Unit Testing in Detail
  2. Additional Features in PHPUnit
  3. Adding More Test Conditions
  4. Adding Listeners
By: Sams Publishing
Rating: starstarstarstarstar / 2
October 26, 2006

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Separate Test Packaging

Given the drawbacks to inlining tests, I choose to avoid that strategy and write my tests in their own files. For exterior tests, there are a number of different philosophies. Some people prefer to go the route of creating a t or tests subdirectory in each library directory for depositing test code. (This method has been the standard method for regression testing in Perl and was recently adopted for testing the PHP source build tree.) Others opt to place tests directly alongside their source files. There are organizational benefits to both of these methods, so it is largely a personal choice. To keep our examples clean here, I use the latter approach. For every library.inc file, you need to create a library.phpt file that contains all the PHPUnit_Framework_TestCase objects you define for it.

In your test script you can use a trick similar to one that you used earlier in this chapter: You can wrap a PHPUnit_Framework_TestSuite creation and run a check to see whether the test code is being executed directly. That way, you can easily run the particular tests in that file (by executing directly) or include them in a larger testing harness.

EmailAddress.phpt looks like this:

<?php
require_once "EmailAddress.inc";
require_once 'PHPUnit/Framework/TestSuite.php';
require_once 'PHPUnit/TextUI/TestRunner.php';
class EmailAddressTestCase extends
PHPUnit_Framework_TestCase { public function _ _construct($name) { parent::_ _construct($name); } public function testLocalPart() { $email = new EmailAddress("george@omniti.com"); // check that the local part of the address is
equal to 'george' $this->assertTrue($email->localPart == 'george') ; } public function testDomain() { $email = new EmailAddress("george@omniti.com"); $this->assertTrue($email->domain == 'omniti.com'); } } if(realpath($_SERVER[PHP_SELF]) == _ _FILE_ _) { $suite = new
PHPUnit_Framework_TestSuite('EmailAddressTestCase'); PHPUnit_TextUI_TestRunner::run($suite); } ?>

In addition to being able to include tests as part of a larger harness, you can execute EmailAddress.phpt directly, to run just its own tests:

PHPUnit 1.0.0-dev by Sebastian Bergmann.
..
Time: 0.0028760433197
OK (2 tests)

Running Multiple Tests Simultaneously

As the size of an application grows, refactoring can easily become a nightmare. I have seen million-line code bases where bugs went unaddressed simply because the code was tied to too many critical components to risk breaking. The real problem was not that the code was too pervasively used; rather, it was that there was no reliable way to test the components of the application to determine the impact of any refactoring.

I'm a lazy guy. I think most developers are also lazy, and this is not necessarily a vice. As easy as it is to write a single regression test, if there is no easy way to test my entire application, I test only the part that is easy. Fortunately, it's easy to bundle a number of distinct TestCase objects into a larger regression test. To run multiple TestCase objects in a single suite, you simply use the addTestSuite() method to add the class to the suite. Here's how you do it:

<?php
require_once "EmailAddress.phpt";
require_once "Text/Word.phpt";
require_once "PHPUnit/Framework/TestSuite.php";
require_once "PHPUnit/TextUI/TestRunner.php";
$suite = new PHPUnit_Framework_TestSuite();
$suite->addTestSuite('EmailAddressTestCase');
$suite->addTestSuite('Text/WordTestCase');
PHPUnit_TextUI_TestRunner::run($suite);
?>

Alternatively, you can take a cue from the autoregistration ability of PHPUnit_Framework_TestSuite to make a fully autoregistering testing harness. Similarly to the naming convention for test methods to be autoloaded, you can require that all autoloadable PHPUnit_Framework_TestCase subclasses have names that end in TestCase. You can then look through the list of declared classes and add all matching classes to the master suite. Here's how this works:

<?php
require_once "PHPUnit/FrameWork/TestSuite.php";
class TestHarness extends
PHPUnit_Framework_TestSuite { private $seen = array(); public function _ _construct() { $this = parent::_ _construct(); foreach( get_declared_classes() as $class) { $this->seen[$class] = 1; } } public function register($file) { require_once($file); foreach( get_declared_classes() as $class) { if(array_key_exists($class, $this->seen)) { continue; } $this->seen[$class] = 1; // ZE lower-cases class names, so we look for
"testcase" if(substr($class, -8, 8) == 'testcase') { print "adding $class\n"; $this->addTestSuite($class); } } } } ?>

To use the TestHarness class, you simply need to register the files that contain the test classes, and if their names end in TestCase, they will be registered and run. In the following example, you write a wrapper that uses TestHarness to autoload all the test cases in EmailAddress.phpt and Text/Word.phpt:

<?php
require_once "TestHarness.php";
require_once "PHPUnit/TextUI/TestRunner.php";
$suite = new TestHarness();
$suite->register("EmailAddress.phpt");
$suite->register("Text/Word.phpt");
PHPUnit_TextUI_TestRunner::run($suite);
?>

This makes it easy to automatically run all the PHPUnit_Framework_TestCase objects for a project from one central location. This is a blessing when you're refactoring central libraries in an API that could affect a number of disparate parts of the application.



 
 
>>> More PHP Articles          >>> More By Sams Publishing
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: