Chapter 3. PHPUnit's GoalsSo 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:
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:
There are two main clashes within this group of constraints:
PHPUnit attempts to resolve these conflicts by using PHP as the testing language. Sometimes the full power of PHP is overkill for writing short, straight-line tests, but by using PHP, we leverage all the experience and tools programmers already have in place. Because we are trying to convince reluctant testers, lowering the barrier to writing those initial tests is particularly important. PHPUnit errs on the side of isolation over quick execution. Isolated tests are valuable because they provide high-quality feedback. You do not get a report with a bunch of test failures that were really caused because one test at the beginning of the suite failed and left the world messed up for the rest of the tests. This orientation toward isolated tests encourages designs with a large number of simple objects. Each object can be tested quickly in isolation. The result is better designs and faster tests. PHPUnit assumes that most tests succeed, and it is not worth reporting the details of successful tests. When a test fails, that fact is worth noting and reporting. The vast majority of tests should succeed and are not worth commenting on, except to count the number of tests that run. This is an assumption that is really built into the reporting classes and not into the core of PHPUnit. When the results of a test run are reported, you see how many tests were executed, but you only see details for those that failed. Tests are expected to be fine-grained, testing one aspect of one object. Hence, the first time a test fails, execution of the test halts, and PHPUnit reports the failure. It is an art to test by running many small tests. Fine-grained tests improve the overall design of the system. When you test an object with PHPUnit, you do so only through the object's public interface. Testing based only on publicly visible behavior encourages you to confront and solve difficult design problems before the results of poor design can affect large parts of the system. |