如何为调用同一类的其他方法但不返回值的方法编写单元测试?(假设使用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()
?
好的!我想明白了!正如预期的那样,模拟正是我在这种情况下所需要的——而模拟兄弟方法被称为部分模拟。在Juan Treminio的这篇文章中有一些关于PHPUnit mock的非常好的信息。
所以要在上面的类中测试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和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
来更新您的配置。
虽然您的mock测试确实达到了您的目标,但我认为您已经降低了对代码的信心。将原始的简单方法与测试它的复杂方法进行比较。被测试的方法失败的唯一原因是忘记添加一个方法调用或键入错误的名称。但是您现在很有可能使用所有这些附加代码来执行此操作,而且它没有任何测试!
规则:如果你的测试代码比被测代码更复杂,它需要自己的测试。
鉴于上述情况,您最好找到另一种方法来测试原始代码。对于编写的方法——三个没有参数的方法调用——肉眼检查就足够了。但我怀疑这个方法在某些地方确实有一些副作用,否则你可以删除它。
单元测试是将类作为一个单元进行测试,而不是单独测试每个方法。单独测试每个方法是一个很好的指示,表明您在编写代码之后编写测试。使用测试驱动开发并首先编写测试将帮助您设计一个更易于测试的更好的类。