BUY THIS BOOK
Add to Cart

Print Book $9.95


Add to Cart

PDF $7.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £6.95

What is this?

Looking to Reprint or License this content?


PHPUnit Pocket Guide
PHPUnit Pocket Guide

By Sebastian Bergmann
Book Price: $9.95 USD
£6.95 GBP
PDF Price: $7.99

Cover | Table of Contents


Table of Contents

Chapter 1: Introduction
For a very long time, my answer to the question, "When will you write documentation for PHPUnit?" has been, "You do not need documentation for PHPUnit. Just read the documentation for JUnit or buy a book on JUnit and adapt the code examples from Java™ and JUnit to PHP and PHPUnit." When I mentioned this to Barbara Weiss and Alexandra Follenius from the O'Reilly Germany office, they encouraged me to think it over and write a book that would serve as the documentation for PHPUnit.
The topic of this book is PHPUnit, an open source framework for test-driven development with the PHP programming language. This book covers Version 2.3 of PHPUnit, which requires PHP 5.1. However, most of the examples should work with PHPUnit Versions 2.0–2.2, as well as PHP 5.0. The "PHPUnit for PHP 4" section, later in this book, covers the older, no longer actively developed version of PHPUnit for PHP 4.
The reader should have a good understanding of object-oriented programming with PHP 5. To German readers, I recommend my book Professionelle Softwareentwicklung mit PHP 5 as an introduction to object-oriented programming with PHP 5. A good English book on the subject is PHP 5 Power Programming by Andi Gutmans, Stig Bakken, and Derick Rethans (Prentice Hall PTR).
This book is available under the Creative Commons license. You will always find the latest version of this book at its web site: http://www.phpunit.de/pocket_guide/. You may distribute and make changes to this book however you wish. Of course, rather than distribute your own private version of the book, I would prefer you send feedback and patches to sb@sebastian-bergmann.de.
The following is a list of the typographical conventions used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, file extensions, pathnames, directories, and Unix utilities.
Constant width
Indicates commands, options, switches, variables, functions, classes, namespaces, methods, modules, parameters, values, objects, the contents of files, or the output from commands.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Requirements
The topic of this book is PHPUnit, an open source framework for test-driven development with the PHP programming language. This book covers Version 2.3 of PHPUnit, which requires PHP 5.1. However, most of the examples should work with PHPUnit Versions 2.0–2.2, as well as PHP 5.0. The "PHPUnit for PHP 4" section, later in this book, covers the older, no longer actively developed version of PHPUnit for PHP 4.
The reader should have a good understanding of object-oriented programming with PHP 5. To German readers, I recommend my book Professionelle Softwareentwicklung mit PHP 5 as an introduction to object-oriented programming with PHP 5. A good English book on the subject is PHP 5 Power Programming by Andi Gutmans, Stig Bakken, and Derick Rethans (Prentice Hall PTR).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
This Book Is Free
This book is available under the Creative Commons license. You will always find the latest version of this book at its web site: http://www.phpunit.de/pocket_guide/. You may distribute and make changes to this book however you wish. Of course, rather than distribute your own private version of the book, I would prefer you send feedback and patches to sb@sebastian-bergmann.de.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Conventions Used in This Book
The following is a list of the typographical conventions used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, file extensions, pathnames, directories, and Unix utilities.
Constant width
Indicates commands, options, switches, variables, functions, classes, namespaces, methods, modules, parameters, values, objects, the contents of files, or the output from commands.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values.
You should pay special attention to notes set apart from the text with the following styles:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
How to Contact Us
We have tested and verified the information in this book to the best of our ability, but you may find that features have changed (or even that we have made mistakes!).
As a reader of this book, you can help us to improve future editions by sending us your feedback. Please let us know about any errors, inaccuracies, bugs, misleading or confusing statements, and typos that you find anywhere in this book.
Please also let us know what we can do to make this book more useful to you. We take your comments seriously and will try to incorporate reasonable suggestions into future editions. You can write to us at:
O'Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
(800) 998-9938 (in the U.S. or Canada)
(707) 829-0515 (international/local)
(707) 829-0104 (fax)
To ask technical questions or to comment on the book, send email to:
The web site for PHPUnit Pocket Guide lists examples, errata, and plans for future editions. You can find this page at:
http://www.oreilly.com/catalog/pupg
For more information about this book and others, see the O'Reilly web site:
http://www.oreilly.com
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Acknowledgments
I would like to thank Kent Beck and Erich Gamma for JUnit and for the inspiration to write PHPUnit. I would also like to thank Kent Beck for his JUnit Pocket Guide, which sparked the idea for this book. I would like to thank Allison Randal, Alexandra Follenius, and Barbara Weiss for sponsoring this book at O'Reilly.
I would like to thank Andi Gutmans, Zeev Suraski, and Marcus Börger for their work on the Zend Engine 2, the core of PHP 5. I would like to thank Derick Rethans for Xdebug, the PHP extension that makes PHPUnit's code-coverage functionality possible. Finally, I would like to thank Michiel Rook, who wrote the PHPUnit tasks for Phing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Automating Tests
Even good programmers make mistakes. The difference between a good programmer and a bad programmer is that the good programmer uses tests to detect his mistakes as soon as possible. The sooner you test for a mistake, the greater your chance of finding it, and the less it will cost to find and fix. This explains why it is so problematic to leave testing until just before releasing software. Most errors do not get caught at all, and the cost of fixing the ones you do catch is so high that you have to perform triage with the errors because you just cannot afford to fix them all.
Testing with PHPUnit is not a totally different activity from what you should already be doing. It is just a different way of doing it. The difference is between testing—that is, checking that your program behaves as expected—and performing a battery of tests—runnable code-fragments that automatically test the correctness of parts (units) of the software. These runnable code-fragments are called unit tests.
In this section, we will go from simple print-based testing code to a fully automated test. Imagine that we have been asked to test PHP's built-in Array. One bit of functionality to test is the function sizeof( ). For a newly created array, we expect the sizeof( ) function to return 0. After we add an element, sizeof( ) should return 1. Example 1 shows what we want to test.
Example 1. Testing Array and sizeof( )
<?php
$fixture = Array( );
// $fixture is expected to be empty.

$fixture[] = "element";
// $fixture is expected to contain one element.
?>
A really simple way to check whether we are getting the results we expect is to print the result of sizeof( ) before and after adding the element (see Example 2). If we get 0 and then 1, Array and sizeof( ) are behaving as expected.
Example 2. Using print to test Array and sizeof( )
<?php
$fixture = Array( );
print sizeof($fixture) . "\n";

$fixture[] = "element";
print sizeof($fixture) . "\n";
?>
0
1
Now, we would like to move from tests that require manual interpretation to tests that can run automatically. In Example 3, we write the comparison of the expected and actual values into the test code and print
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: PHPUnit's Goals
So far, we only have two tests for the Array built-in and the sizeof( ) function. When we start to test the numerous array_*( ) functions PHP offers, we will need to write a test for each of them. We could write all these tests from scratch. However, it is much better to write a testing infrastructure once and then write only the unique parts of each test. PHPUnit is such an infrastructure.
Example 5 shows how we have to rewrite our two tests from Example 4 so that we can use them with PHPUnit.
Example 5. Testing Array and sizeof( ) with PHPUnit
<?php
require_once 'PHPUnit2/Framework/TestCase.php';

class ArrayTest extends PHPUnit2_Framework_TestCase {
  public function testNewArrayIsEmpty( ) {
    // Create the Array fixture.
    $fixture = Array( );

    // Assert that the size of the Array fixture is 0. 
    $this->assertEquals(0, sizeof($fixture)); 
  }
  public function testArrayContainsAnElement( ) { 
    // Create the Array fixture.    
		$fixture = Array( );

    // Add an element to the Array fixture.    
		$fixture[] = 'Element';
 
		// Assert that the size of the Array fixture is 1. 
		$this->assertEquals(1, sizeof($fixture));
  }
}
?>
Example 5 shows the basic steps for writing tests with PHPUnit:
  1. The tests for a class Class go into a class ClassTest.
  2. ClassTest inherits (most of the time) from PHPUnit2_ Framework_TestCase.
  3. The tests are public methods that expect no parameters and are named test*.
  4. Inside the test methods, assertion methods such as assertEquals( ) (see Table 6) are used to assert that an actual value matches an expected value.
A framework such as PHPUnit has to resolve a set of constraints, some of which seem to conflict with each other. Simultaneously, tests should be:
Easy to learn to write.
Tests should be easy to learn to write; otherwise, developers will not learn to write them.
Easy to write.
Tests should be easy to write; otherwise, developers will not write them.
Easy to read.
Test code should contain no extraneous overhead so that the test itself does not get lost in the noise that surrounds it.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Installing PHPUnit
PHPUnit is available from the PHP Extension and Application Repository (PEAR), which is a framework and distribution system for reusable PHP components. It can be installed using the PEAR Installer:
	$ pear install PHPUnit2
Due to PEAR's version-naming standard, the PHPUnit package for PHP 5 is called PHPUnit2. PHPUnit is the name of the PHPUnit package for PHP 4 that is the topic of "PHPUnit for PHP 4," later in this book.
After the installation, you can find the PHPUnit source files inside your local PEAR directory; the path is usually /usr/lib/ php/PHPUnit2.
Although using the PEAR installer is the only supported way to install PHPUnit, you can install PHPUnit manually. For manual installation, do the following:
  1. Download a release archive from http://pear.php.net/package/PHPUnit2/download and extract it to a directory that is listed in the include_path of your php.ini configuration file.
  2. Prepare the phpunit script:
    1. Rename the pear-phpunit script to phpunit.
    2. Replace the @php_bin@ string in it with the path to your PHP command-line interpreter (usually /usr/bin/ php).
    3. Copy it to a directory that is in your PATH and make it executable (chmod +x phpunit).
  3. Replace the @package_version@ string in the PHPUnit2/ Runner/Version.php script with the version number of the PHPUnit release you are installing (2.3.0, for instance).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: The Command-Line Test Runner
The PHPUnit command-line test runner is invoked through the phpunit command. The following code shows how to run tests with the PHPUnit command-line test runner:
phpunit ArrayTest
PHPUnit 2.3.0 by Sebastian Bergmann.

..

Time: 0.067288

OK (2 tests)
For each test run, the PHPUnit command-line tool prints one character to indicate progress:
. Printed when the test succeeds.
F Printed when an assertion fails while running the test method.
E Printed when an error occurs while running the test method.
I Printed when the test is marked as being incomplete or not yet implemented (see "Incomplete Tests," later in this book).
PHPUnit distinguishes between failures and errors. A failure is a violated PHPUnit assertion. An error is an unexpected exception or a PHP error. Sometimes this distinction proves useful because errors tend to be easier to fix than failures. If you have a big list of problems, it's best to tackle the errors first and see if you have any failures left when the errors are all fixed.
Let's take a look at the command-line test runner's switches in the following code:

phpunit --help
PHPUnit 2.3.0 by Sebastian Bergmann.

Usage: phpunit [switches] UnitTest [UnitTest.php]
 --coverage-data <file> Write code-coverage data in raw
             format to file.

 --coverage-html <file> Write code-coverage data in HTML
             format to file.
 --coverage-text <file> Write code-coverage data in text
             format to file.

 --testdox-html <file> Write agile documentation in HTML
             format to file.
 --testdox-text <file> Write agile documentation in Text
             format to file.

 --log-xml <file>    Log test progress in XML format
             to file.

 --loader <loader>   TestSuiteLoader implementation to
             use.

 --skeleton       Generate skeleton UnitTest class
             for Unit in Unit.php.

 --wait         Waits for a keystroke after each
             test.

 --help         Prints this usage information.

 --version       Prints the version and exits.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 6: Fixtures
One of the most time consuming parts of writing tests is writing the code to set up the world in a known state and then return it to its original state when the test is complete. The known state is called the fixture of the test.
In Example 5, the fixture was simply an array stored in the $fixture variable. Most of the time, though, the fixture will be more complex than a simple array, and the amount of code needed to set it up will grow accordingly. The actual content of the test gets lost in the noise of setting up the fixture. This problem gets even worse when you write several tests with similar fixtures. Without some help from the testing framework, we would have to duplicate the code that sets up the fixture for each test we write.
PHPUnit supports sharing the setup code. Before a test method is run, a template method called setUp( ) is invoked. setUp( ) is where you create the objects against which you will test. Once the test method has finished running, whether it succeeded or failed, another template method called tearDown( ) is invoked. tearDown( ) is where you clean up the objects against which you tested.
We can now refactor Example 5 and use setUp( ) to eliminate the code duplication that we had before. First, we declare the instance variable, $fixture, that we are going to use instead of a method-local variable. Then, we put the creation of the Array fixture into the setUp( ) method. Finally, we remove the redundant code from the test methods and use the newly introduced instance variable, $this->fixture, instead of the method-local variable $fixture with the assertEquals( ) assertion method.
	<?php 
	require_once 'PHPUnit2/Framework/TestCase.php';

	class ArrayTest extends PHPUnit2_Framework_TestCase { 
    protected $fixture;

    protected function setUp( ) {
      // Create the Array fixture.
      $this->fixture = Array( );
    }


		public function testNewArrayIsEmpty( ) {
      // Assert that the size of the Array fixture is 0.
			$this->assertEquals(0, sizeof($this->fixture)); 
    }

    public function testArrayContainsAnElement( ) { 
      // Add an element to the Array fixture.    
      $this->fixture[] = 'Element';

			// Assert that the size of the Array fixture is 1.
			$this->assertEquals(1, sizeof($this->fixture));
    }
  }
  ?>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
More setUp( ) than tearDown( )
setUp( ) and tearDown( ) are nicely symmetrical in theory but not in practice. In practice, you only need to implement tearDown( ) if you have allocated external resources such as files or sockets in setUp( ). If your setUp( ) just creates plain PHP objects, you can generally ignore tearDown( ). However, if you create many objects in your setUp( ), you might want to unset( ) the variables pointing to those objects in your tearDown( ) so they can be garbage collected. The garbage collection of test-case objects is not predictable.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Variations
What happens when you have two tests with slightly different setups? There are two possibilities:
  • If the setUp( ) code differs only slightly, move the code that differs from the setUp( ) code to the test method.
  • If you really have a different setUp( ), you need a different test-case class. Name the class after the difference in the setup.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Suite-Level Setup
PHPUnit does not provide convenient support for suite-level setup. There aren't many good reasons to share fixtures between tests, but, in most cases, the need to do so stems from an unresolved design problem.
A good example of a fixture that makes sense to share across several tests is a database connection: you log into the database once and reuse the database connection instead of creating a new connection for each test. This makes your tests run faster. To do this, write your database tests in a test-case class named DatabaseTests, and wrap the test suite in a TestSetup decorator object that overrides setUp( ) to open the database connection and tearDown( ) to close the connection, as shown in Example 6. You can run the tests from DatabaseTests through the DatabaseTestSetup decorator by invoking, for instance, PHPUnit's command-line test runner with phpunit DatabaseTestSetup.
Example 6. Writing a suite-level setup decorator
<?php
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'PHPUnit2/Extensions/TestSetup.php';

class DatabaseTestSetup extends PHPUnit2_Extensions_TestSetup 
{
  protected $connection = NULL;

  protected function setUp( ) {
    $this->connection = new PDO(
     'mysql:host=wopr;dbname=test',
		 'root',
		 ''
    );
  }

  protected function tearDown( ) {
    $this->connection = NULL;
  }

  public static function suite( ) {
    return new DatabaseTestSetup(
     new PHPUnit2_Framework_TestSuite('DatabaseTests')
    );
  }
}
?>
It cannot be emphasized enough that sharing fixtures between tests reduces the value of the tests. The underlying design problem is that objects are too closely bound together. You will achieve better results by solving the underlying design problem and then writing tests using stubs (see the section "Stubs," later in this book), than by creating dependencies between tests at runtime and ignoring the opportunity to improve your design.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 7: Testing Exceptions and Performance Regressions
PHPUnit provides two extensions that aid in the writing of tests for exceptions and performance regressions to the standard base class for test classes, PHPUnit2_Framework_TestCase.
How do you test exceptions? You cannot assert directly that they are raised. Instead, you have to use PHP's exception handling facilities to write the test. The following example demonstrates testing exceptions:
	<?php
	require_once 'PHPUnit2/Framework/TestCase.php';

	class ExceptionTest extends PHPUnit2_Framework_TestCase {
    public function testException( ) {
      try {
        // … Code that is expected to raise an
				// Exception …
				$this->fail('No Exception has been raised.');
      }

      catch (Exception $expected) {
			}
    }
  }
  ?>
If the code that is expected to raise an exception does not raise an exception, the subsequent call to fail( ) (see Table 7, later in this book) will halt the test and signal a problem with the test. If the expected exception is raised, the catch block will be executed, and the test will continue executing.
Alternatively, you can extend your test class from PHPUnit2_ Extensions_ExceptionTestCase to test whether an exception is thrown inside the tested code. Example 7 shows how to subclass PHPUnit2_Extensions_ExceptionTestCase and use its setExpectedException( ) method to set the expected exception. If this expected exception is not thrown, the test will be counted as a failure.
Example 7. Using PHPUnit2_Extensions_ExceptionTestCase
<?php 
require_once 'PHPUnit2/Extensions/ExceptionTestCase.php';

class ExceptionTest extends PHPUnit2_Extensions_
ExceptionTestCase {
	public function testException( ) {
		$this->setExpectedException('Exception');

  }
}
?>

phpunit ExceptionTest
PHPUnit 2.3.0 by Sebastian Bergmann.

F

Time: 0.006798
There was 1 failure:
1) testException(ExceptionTest)
Expected exception Exception

FAILURES!!!
Tests run: 1, Failures: 1, Errors: 0, Incomplete Tests: 0.
Table 1 shows the external protocol implemented by PHPUnit2_Extensions_ExceptionTestCase.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Exceptions
How do you test exceptions? You cannot assert directly that they are raised. Instead, you have to use PHP's exception handling facilities to write the test. The following example demonstrates testing exceptions:
	<?php
	require_once 'PHPUnit2/Framework/TestCase.php';

	class ExceptionTest extends PHPUnit2_Framework_TestCase {
    public function testException( ) {
      try {
        // … Code that is expected to raise an
				// Exception …
				$this->fail('No Exception has been raised.');
      }

      catch (Exception $expected) {
			}
    }
  }
  ?>
If the code that is expected to raise an exception does not raise an exception, the subsequent call to fail( ) (see Table 7, later in this book) will halt the test and signal a problem with the test. If the expected exception is raised, the catch block will be executed, and the test will continue executing.
Alternatively, you can extend your test class from PHPUnit2_ Extensions_ExceptionTestCase to test whether an exception is thrown inside the tested code. Example 7 shows how to subclass PHPUnit2_Extensions_ExceptionTestCase and use its setExpectedException( ) method to set the expected exception. If this expected exception is not thrown, the test will be counted as a failure.
Example 7. Using PHPUnit2_Extensions_ExceptionTestCase
<?php 
require_once 'PHPUnit2/Extensions/ExceptionTestCase.php';

class ExceptionTest extends PHPUnit2_Extensions_
ExceptionTestCase {
	public function testException( ) {
		$this->setExpectedException('Exception');

  }
}
?>

phpunit ExceptionTest
PHPUnit 2.3.0 by Sebastian Bergmann.

F

Time: 0.006798
There was 1 failure:
1) testException(ExceptionTest)
Expected exception Exception

FAILURES!!!
Tests run: 1, Failures: 1, Errors: 0, Incomplete Tests: 0.
Table 1 shows the external protocol implemented by PHPUnit2_Extensions_ExceptionTestCase.
Table 1: Extension TestCase external protocols
Method
Description
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Performance Regressions
You can extend your test class from PHPUnit2_Extensions_ PerformanceTestCase to test whether the execution of a function or a method call, for instance, exceeds a specified time limit.
Example 8 shows how to subclass PHPUnit2_Extensions_ PerformanceTestCase and use its setMaxRunningTime( ) method to set the maximum running time for the test. If the test is not executed within this time limit, it will be counted as a failure.
Example 8. Using PHPUnit2_Extensions_PerformanceTestCase
<?php 
require_once 'PHPUnit2/Extensions/PerformanceTestCase.php';

class PerformanceTest extends PHPUnit2_Extensions_ 
PerformanceTestCase {
  public function testPerformance( ) {
		$this->setMaxRunningTime(2);
		sleep(1);
	} 
} 
?>
Table 2 shows the external protocol implemented by PHPUnit2_Extensions_PerformanceTestCase.
Table 2: Performance TestCase external protocols
Method
Description
void setMaxRunningTime(integer $maxRunningTime)
Sets the maximum running time for the test to $maxRunningTime (in seconds)..
integer getMaxRunningTime( )
Returns the maximum running time allowed for the test.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 8: Incomplete Tests
When you are working on a new test-case class, you might want to begin by writing empty test methods, such as:
	public function testSomething( ) {
	}
to keep track of the tests that you have to write. The problem with empty test methods is that they are interpreted as a success by the PHPUnit framework. This misinterpretation leads to the test reports being useless—you cannot see whether a test is actually successful or just not yet implemented. Calling $this->fail( ) in the unimplemented test method does not help either because then the test will be interpreted as a failure. This would be just as wrong as interpreting an unimplemented test as a success.
If we think of a successful test as a green light, and a test failure as a red light, we need an additional yellow light to mark a test as being incomplete or not yet implemented. PHPUnit2_ Framework_IncompleteTest is a marker interface for marking an exception that is raised by a test method as the result of the test being incomplete or not currently implemented. PHPUnit2_Framework_IncompleteTestError is the standard implementation of this interface.
Example 9 shows a test-case class, SampleTest, that contains one test method, testSomething( ). By raising the PHPUnit2_ Framework_IncompleteTestError exception in the test method, we mark the test as being incomplete.
Example 9. Marking a test as incomplete
<?php
require_once 'PHPUnit2/Framework/TestCase.php';
require_once 'PHPUnit2/Framework/IncompleteTestError.php';

class SampleTest extends PHPUnit2_Framework_TestCase {
	public function testSomething( ) {
		// Optional: Test anything here, if you want.
		$this->assertTrue(TRUE, 'This should already work.');

		// Stop here and mark this test as incomplete. 
		// You could use any Exception which implements the 
		// PHPUnit2_Framework_IncompleteTest interface. 
		throw new PHPUnit2_Framework_IncompleteTestError(
     'This test has not been implemented yet.' 
    );
	}
}
?>
An incomplete test is denoted by an I in the output of the PHPUnit command-line test runner, as shown in the following example:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 9: Test-First Programming
Unit tests are a vital part of several software development practices and processes, such as test-first programming, Extreme Programming, and test-driven development. They also allow for design-by-contract in programming languages that do not support this methodology with language constructs.
You can use PHPUnit to write tests once you are done programming. However, the sooner a test is written after an error has been introduced, the more valuable the test is. So, instead of writing tests months after the code is "complete," we can write tests days, hours, or minutes after the possible introduction of a defect. Why stop there? Why not write the tests a little before the possible introduction of a defect?
Test-first programming, which is part of Extreme Programming and test-driven development, builds upon this idea and takes it to the extreme. With today's computational power, we have the opportunity to run thousands of tests, thousands of times per day. We can use the feedback from all of these tests to program in small steps, each of which carries with it the assurance of a new automated test, in addition to all the tests that have come before. The tests are like pitons, assuring you that no matter what happens, once you have made progress, you can only fall so far.
When you first write the test, it cannot possibly run because you are calling on objects and methods that have not been programmed yet. This might feel strange at first, but, after a while, you will get used to it. Think of test-first programming as a pragmatic approach to following the object-oriented programming principle of programming to an interface instead of programming to an implementation: while you are writing the test, you are thinking about the interface of the object you are testing—what does this object look like from the outside? When you go to make the test really work, you are thinking about pure implementation. The interface is fixed by the failing test.
What follows is a necessarily abbreviated introduction to test-first programming. You can explore the topic further in other books, such as
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
BankAccount Example
In this section, we will look at the example of a class that represents a bank account. The contract for the BankAccount class requires methods to get and set the bank account's balance, as well as methods to deposit and withdraw money. It also specifies that the following two conditions must be ensured:
  • The bank account's initial balance must be zero.
  • The bank account's balance cannot become negative.
Following the test-first programming approach, we write the tests for the BankAccount class before we write the code for the class itself. We use the contract conditions as the basis for the tests and name the test methods accordingly, as shown in Example 10.
Example 10. Tests for the BankAccount class
<?php
require_once 'PHPUnit2/Framework/TestCase.php';
require_once 'BankAccount.php';

class BankAccountTest extends PHPUnit2_Framework_TestCase { 
  private $ba;

  protected function setUp( ) {
		$this->ba = new BankAccount;
	}

  public function testBalanceIsInitiallyZero( ) {    
		$this->assertEquals(0, $this->ba->getBalance( )); 
  }

  public function testBalanceCannotBecomeNegative( ) { 
    try { 
      $this->ba->withdrawMoney(1); 
    }


		catch (Exception $e) {
			return;
    }

    $this->fail( );
  }

  public function testBalanceCannotBecomeNegative2( ) { 
		try { 
			$this->ba->depositMoney(-1); 
		}

		catch (Exception $e) {
			return;
    }

    $this->fail( );
  }

  public function testBalanceCannotBecomeNegative3( ) { 
    try { 
      $this->ba->setBalance(-1); 
    }

		catch (Exception $e) {
			return;
    }

    $this->fail( );
  }
}
?>
We now write the minimal amount of code needed for the first test, testBalanceIsInitiallyZero( ), to pass. In our example, this amounts to implementing the getBalance( ) method of the BankAccount class, as shown in Example 11.
Example 11. Code needed for the testBalanceIsInitiallyZero( ) test to pass
<?php
class BankAccount {
	private $balance = 0;

  public function getBalance( ) {
		return $this->balance;

  }
}
?>
The test for the first contract condition now passes, but the tests for the second contract condition fail because we have yet to implement the methods that these tests call:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 10: Code-Coverage Analysis
You have learned how to use unit tests to test your code. But how do you test your tests? How do you find code that is not yet tested—or, in other words, not yet covered by a test? How do you measure testing completeness? All these questions are answered by a practice called code-coverage analysis. Code-coverage analysis gives you an insight into what parts of the production code are executed when the tests are run.
PHPUnit's code-coverage analysis utilizes the statement coverage functionality provided by the Xdebug extension. An example of what statement coverage means is that if there is a method with 100 lines of code, and only 75 of these lines are actually executed when tests are being run, then the method is considered to have a code overage of 75 percent.
Figure 1 shows a code-coverage report for the BankAccount class (from Example 12) in HTML format generated by the PHPUnit command-line test runner's --coverage-html switch. Executable code lines are black; non-executable code lines are gray. Code lines that are actually executed are highlighted.
Figure 1-1: The BankAccount class, not completely covered by tests
The code-coverage report shows that we need to write tests that call setBalance( ), depositMoney( ), and withdrawMoney( ) with legal values in order to achieve complete code coverage. Example 14 shows tests that need to be added to the BankAccountTest test-case class to completely cover the BankAccount class.
Example 14. The BankAccount class, covered by tests
<?php
require_once 'PHPUnit2/Framework/TestCase.php';
require_once 'BankAccount.php';

class BankAccountTest extends PHPUnit2_Framework_TestCase { 
	// …

	public function testSetBalance( ) {
		$this->ba->setBalance(1);
		$this->assertEquals(1, $this->ba->getBalance( )); 
  }

  public function testDepositAndWidthdrawMoney( ) { 
		$this->ba->depositMoney(1);    
		$this->assertEquals(1, $this->ba->getBalance( ));

		$this->ba->withdrawMoney(1);
    $this->assertEquals(0, $this->ba->getBalance( ));
  }
}
?>
In Figure 2, we see that the BankAccount
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 11: Stubs
Tests that only test one thing are more informative than tests in which failure can come from many sources. How can you isolate your tests from external influences? Simply put, by replacing the expensive, messy, unreliable, slow, complicated resources with stubs made from plain PHP objects. For example, you can implement what is in reality a complicated computation by returning a constant, at least for the purposes of a single test.
Stubs solve the problem of allocating expensive external resources. For example, sharing a resource, such as a database connection, between tests by using the PHPUnit2_ Extensions_TestSetup decorator helps, but not using the database for the purposes of the tests at all is even better.
Figure 1-2: The BankAccount class is completely covered by tests
Design improvement is one effect of using stubs. Widely used resources are accessed through a single façade, so you can easily replace the resource with the stub. For example, instead of having direct database calls scattered throughout the code, you have a single Database object—an implementor of the IDatabase interface. Then, you can create a stub implementation of IDatabase and use it for your tests. You can even create an option for running the tests with the stub database or the real database, so you can use your tests for both local testing during development and integration testing with the real database.
Functionality that needs to be stubbed out tends to cluster in the same object, improving cohesion. By presenting the functionality with a single, coherent interface, you reduce the coupling with the rest of the system.
Sometimes you need to check that an object has been called correctly. You can create a complete stub of the object to be called, but that can make it inconvenient to check for correct results. A simpler solution is to apply the self-shunt pattern and use the test-case object itself as a stub. The term selfshunting is taken from the medical practice of installing a tube that takes blood from an artery and returns it to a vein to provide a convenient place for injecting drugs.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Self-Shunting
Sometimes you need to check that an object has been called correctly. You can create a complete stub of the object to be called, but that can make it inconvenient to check for correct results. A simpler solution is to apply the self-shunt pattern and use the test-case object itself as a stub. The term selfshunting is taken from the medical practice of installing a tube that takes blood from an artery and returns it to a vein to provide a convenient place for injecting drugs.
Here is an example: suppose we want to test that the correct method is called on an object that observes another object. First, we make our test-case class an implementor of Observer:
	class ObserverTest extends PHPUnit2_Framework_TestCase
	implements Observer{
	}
Next, we implement the one Observer method, update( ), to check that it is called when the state of the observed Subject object changes:
	public $wasCalled = FALSE;

	public function update(Subject $subject) {
		$this->wasCalled = TRUE;
	}
Now, we can write our test. We create a new Subject object and attach the test object to it as an observer. When the state of the Subject changes—for instance, by calling its doSomething( ) method—the Subject object has to call the update( ) method on all objects that are registered as observers. We use the $wasCalled instance variable that is set by our implementation of update( ) to check whether the Subject object does what it is supposed to do:
	public function testUpdate( ) {
		$subject = new Subject;
		$subject->attach($this);
		$subject->doSomething( );
		$this->assertTrue($this->wasCalled);
	}
Notice that we create a new Subject object instead of relying on a global instance. Stubbing encourages this style of design. It reduces the coupling between objects and improves reuse.
If you are not familiar with the self-shunt pattern, the tests can be hard to read. What is going on here? Why is a test case also an observer? But once you get used to the idiom, the tests are easy to read. Everything you need to understand a test is in one class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 12: Other Uses for Tests
Once you get used to writing automated tests, you will likely discover more uses for tests. Here are some examples.
Typically, in a project that is developed using an agile process, such as Extreme Programming, the documentation cannot keep up with the frequent changes to the project's design and code. Extreme Programming demands collective code ownership, so all developers need to know how the entire system works. If you are disciplined enough to use "speaking names" for your tests that describe what a class should do, you can use PHPUnit's TestDox functionality to generate automated documentation for your project based on its tests. This documentation gives developers an overview of what each class of the project is supposed to do.
PHPUnit's TestDox functionality looks at a test class and all the test method names and converts them from camel case PHP names to sentences: testBalanceIsInitiallyZero( ) becomes "Balance is initially zero." If there are several test methods whose names differ only by a suffix of one or more digits, such as testBalanceCannotBecomeNegative( ) and testBalanceCannotBecomeNegative2( ), the sentence "Balance cannot become negative" will appear only once, assuming that all of these tests succeed.
The following code shows the agile documentation for the Bank Account class (in Example 10) generated by running phpunit --testdox-text BankAccountTest.txt BankAccountTest:
	BankAccount
	 - Balance is initially zero
	 - Balance cannot become negative
Alternatively, the agile documentation can be generated in HTML format by using --testdox-html BankAccountTest.htm.
Agile documentation can be used to document the assumptions you make about the external packages in your project. When you use an external package, you are exposed to the risks that the package will not behave as you expect, and that future versions of the package will change in subtle ways that will break your code, without you knowing it. You can address these risks by writing a test about how the external package works every time you make an assumption. If your test succeeds, your assumption is valid. If you document all your assumptions with tests, future releases of the external package will be no cause for concern: if the tests succeed, your system should continue working.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Agile Documentation
Typically, in a project that is developed using an agile process, such as Extreme Programming, the documentation cannot keep up with the frequent changes to the project's design and code. Extreme Programming demands collective code ownership, so all developers need to know how the entire system works. If you are disciplined enough to use "speaking names" for your tests that describe what a class should do, you can use PHPUnit's TestDox functionality to generate automated documentation for your project based on its tests. This documentation gives developers an overview of what each class of the project is supposed to do.
PHPUnit's TestDox functionality looks at a test class and all the test method names and converts them from camel case PHP names to sentences: testBalanceIsInitiallyZero( ) becomes "Balance is initially zero." If there are several test methods whose names differ only by a suffix of one or more digits, such as testBalanceCannotBecomeNegative( ) and testBalanceCannotBecomeNegative2( ), the sentence "Balance cannot become negative" will appear only once, assuming that all of these tests succeed.
The following code shows the agile documentation for the Bank Account class (in Example 10) generated by running phpunit --testdox-text BankAccountTest.txt BankAccountTest:
	BankAccount
	 - Balance is initially zero
	 - Balance cannot become negative
Alternatively, the agile documentation can be generated in HTML format by using --testdox-html BankAccountTest.htm.
Agile documentation can be used to document the assumptions you make about the external packages in your project. When you use an external package, you are exposed to the risks that the package will not behave as you expect, and that future versions of the package will change in subtle ways that will break your code, without you knowing it. You can address these risks by writing a test about how the external package works every time you make an assumption. If your test succeeds, your assumption is valid. If you document all your assumptions with tests, future releases of the external package will be no cause for concern: if the tests succeed, your system should continue working.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Cross-Team Tests
When you document assumptions with tests, you own the tests. The supplier of the package—who you make assumptions about—knows nothing about your tests. If you want a closer relationship with the supplier of a package, you can use the tests to communicate and coordinate your activities.
When you agree on coordinating your activities with the supplier of a package, you can write the tests together. Do this in such a way that the tests reveal as many assumptions as possible. Hidden assumptions are the death of cooperation. With the tests, you document exactly what you expect from the supplied package. The supplier will know the package is complete when all the tests run.
By using stubs (see the section "Stubs," earlier in this book), you can further decouple yourself from the supplier. The job of the supplier is to make the tests run with the real implementation of the package. Your job is to make the tests run for your own code. Until such time as you have the real implementation of the supplied package, you use stub objects. Following this approach, the two teams can develop independently.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Debugging Tests
When you get a defect report, your impulse might be to fix the defect as quickly as possible. Experience shows that this impulse will not serve you well; it is likely that the fix for the defect will cause another defect.
You can hold your impulse in check by doing the following:
  1. Verifying that you can reproduce the defect.
  2. Finding the smallest-scale demonstration of the defect in the code. For example, if a number appears incorrectly in an output, find the object that is computing that number.
  3. Writing an automated test that fails but will succeed when the defect is fixed.
  4. Fixing the defect.
Finding the smallest reliable reproduction of the defect gives you the opportunity to really examine the cause of the defect. The test you write will improve the chances that when you fix the defect, you really fix it, because the new test reduces the likelihood of undoing the fix with future code changes.
All the tests you wrote before reduce the likelihood of inadvertently causing a different problem.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Refactoring
Refactoring, the controlled technique for improving the design of an existing code ba