次の実装が与えられます:
class Foo {
public function helper() {
// Does something with external side effects, like updating
// a database or altering the file system.
}
public function bar() {
if ($this->helper() === FALSE) {
throw new Exception(/* ... */);
}
}
}
Foo::bar()
テスト中に副作用を発生させずに単体テストを行うにはどうすればよいFoo::helper()
ですか?
私はモックFoo
とスタブができることを知っていますFoo::helper()
:
public function testGoodBar() {
$mock = $this->getMock('Foo', array('helper'));
$this->expects($this->once())
->method('helper')
->will($this->returnValue(TRUE));
$this->assertTrue($mock->bar());
}
...しかし、これにより、副作用を引き起こす可能性のある他のメソッドを導入するコード変更に対して、テストが広く開かれたままになります。その後、更新せずにテストを再実行すると、テスト自体に永続的な副作用が発生します。
Foo
また、すべてのメソッドがモックされて副作用が発生しないように、モックすることもできます。
public function testGoodBar() {
$mock = $this->getMock('Foo');
$this->expects($this->once())
->method('helper')
->will($this->returnValue(TRUE));
$this->assertTrue($mock->bar());
}
...しかし、Foo::bar()
それは私たちがテストしたい方法なので、それは悪いことです。
私が思いついた唯一の解決策は、テスト対象のメソッドを除くすべてのメソッドを明示的にモックすることです。
public function testGoodBar() {
$mock = $this->getMock('Foo', array_diff(
get_class_methods('Foo'),
'bar'
));
$this->expects($this->once())
->method('helper')
->will($this->returnValue(TRUE));
$this->assertTrue($mock->bar());
}
...しかし、これは厄介なようで、明らかな何かが欠けているように感じます。