Tests that only test one thing are more informative than tests where 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.
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 self-shunting 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? Once you get used to the idiom, the tests are easy to read. Everything you need to understand the test is in one class.