gpt4 book ai didi

php - 我将如何对具有副作用的方法进行单元测试?

转载 作者:搜寻专家 更新时间:2023-10-31 20:46:01 24 4
gpt4 key购买 nike

给定以下实现:

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 和 stub 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());
}

...但这看起来很笨拙,而且我觉得我遗漏了一些明显的东西。

最佳答案

(在回答这个问题时考虑问题下的评论。)

如果您正在扩展一个其唯一目的是产生副作用的类,我希望所有扩展代码也会产生副作用。因此,您必须在测试中考虑到这一点,并设置一个环境,您可以在其中测试具有副作用的代码(即:为该测试启动并运行 memcached 实例)。

如果您不想这样做(可以理解),最好将您的代码以可模拟的方式编写为副作用类的包装器。因此,您的 Foo::__construct 接受产生副作用的类的实例或工厂,因此您可以在测试中模拟它以仅测试无副作用的代码。

关于php - 我将如何对具有副作用的方法进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13254411/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com