FtD*_*Xw6 4 php phpunit unit-testing
鉴于以下实现:
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(/* ... */);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我将如何进行单元测试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());
}
Run Code Online (Sandbox Code Playgroud)
...但这使测试对引入其他可能有副作用的方法的代码更改保持开放。然后如果测试在没有更新的情况下再次运行,测试本身将产生永久性的副作用。
我也可以 mock Foo,这样它的所有方法都会被嘲笑并且不会产生副作用:
public function testGoodBar() {
$mock = $this->getMock('Foo');
$this->expects($this->once())
->method('helper')
->will($this->returnValue(TRUE));
$this->assertTrue($mock->bar());
}
Run Code Online (Sandbox Code Playgroud)
...但随后甚至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());
}
Run Code Online (Sandbox Code Playgroud)
...但这似乎很笨拙,我觉得我错过了一些明显的东西。
(在此答案中考虑问题下的评论。)
如果您正在扩展一个唯一目的是产生副作用的类,我希望所有扩展代码也会产生副作用。因此,您必须在测试中考虑到这一点,并设置一个环境,您可以在其中测试带有副作用的代码(即:为此测试启动并运行 memcached 实例)。
如果您不想要这个(可以理解),最好以一种可模拟的方式将您的代码编写为副作用类的包装器。因此,您Foo::__construct接受产生副作用的类的实例或工厂,因此您可以在测试中模拟它以仅测试您的无副作用代码。
| 归档时间: |
|
| 查看次数: |
1176 次 |
| 最近记录: |