# PHPUnit袖珍指南 第十一章 残根

11-1．自分流

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{
}

public $wasCalled = FALSE; public function update(Subject$subject) {
$this->wasCalled = TRUE; } 现在，可以写测试了。创建一个新的Subject对象,将测试对象附带在对象上作为观察员。但Subject的状态改变时，如调用doSomething()方法，Subject对象就会调用所有注册为观察员的update()方法。通过实现update()，我们用$wasCalled变量来检查Subject是否做了它应该做的事。

public function testUpdate( ) {
$subject = new Subject;$subject->attach($this);$subject->doSomething( );
$this->assertTrue($this->wasCalled);
}

--------------------------------------------------------------------------------------------------------------------

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.

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

11-1. 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 changesfor instance, by calling its doSomething( ) methodthe 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.