如何为调用同一类的其他方法但不返回值的方法编写单元测试? (让我们用PHPUnit说。)
例如,让我们说我有以下课程:
class MyClass {
public function doEverything() {
$this->doA;
$this->doB;
$this->doC;
}
public function doA() {
// do something, return nothing
}
public function doB() {
// do something, return nothing
}
public function doC() {
// do something, return nothing
}
}
您如何测试doEverything()
?
编辑:
我之所以这样问,因为从我所读过的内容来看,似乎每种方法都应该有自己的专用单元测试。当然,你也有功能和集成测试,但那些目标特定的例程,可以这么说(不是每个方法级别)。
但是,如果几乎所有方法都需要自己的单元测试,我认为这将是"最佳实践"对所有上述方法进行单元测试。是/否?
答案 0 :(得分:7)
好!我已经明白了!正如所料,在这种情况下我需要模拟 - 并且模仿兄弟方法被称为部分模拟。在这个article by Juan Treminio中有一些关于PHPUnit模拟的非常好的信息。
所以要在上面的课程中测试doEverything()
,我需要做这样的事情:
public function testDoEverything()
{
// Any methods not specified in setMethods will execute perfectly normally,
// and any methods that ARE specified return null (or whatever you specify)
$mock = $this->getMockBuilder('\MyClass')
->setMethods(array('doA', 'doB', 'doC'))
->getMock();
// doA() should be called once
$mock->expects($this->once())
->method('doA');
// doB() should be called once
$mock->expects($this->once())
->method('doB');
// doC() should be called once
$mock->expects($this->once())
->method('doC');
// Call doEverything and see if it calls the functions like our
// above written expectations specify
$mock->doEverything();
}
就是这样!很简单!
我正在使用Laravel框架以及Codeception,这使得弄清楚它有点棘手。如果你使用Laravel和Codeception,你需要做更多的工作,因为Laravel自动加载不会默认连接到PHPUnit测试。您基本上需要更新unit.suite.yml
以包含Laravel4,如下所示:
# Codeception Test Suite Configuration
# suite for unit (internal) tests.
class_name: UnitTester
modules:
enabled: [Asserts, UnitHelper, Laravel4]
更新文件后,请不要忘记致电php codecept.phar build
更新您的配置。
答案 1 :(得分:2)
虽然您的模拟测试确实实现了您的目标,但我认为您已经降低了对代码的信心。将原始的简单方法与测试它的复杂方法进行比较。被测方法失败的唯一方法是忘记添加其中一个方法调用或输入错误的名称。但是你现在可以用所有额外的代码做到这一点,而且它没有任何测试!
规则:如果您的测试代码比测试中的代码更复杂,则需要自己的测试。
鉴于上述情况,您最好找到另一种方法来测试原始代码。对于所写的方法 - 没有参数的三个方法调用 - 通过眼球检查就足够了。但是我怀疑这个方法在某个地方确实有一些副作用,否则你可以删除它。
单元测试是关于将类作为一个单元进行测试,而不是单独测试每个方法。单独测试每种方法都可以很好地表明您在代码之后编写测试。使用Test Driven Development并首先编写测试将帮助您设计更易于测试的更好的类。