模拟当前被测类的内部函数调用


Mock an internal function call of current class under test

我想测试这个函数:

public function reset()
{
    if(!$this->onBeforeReset())      // Protected, internal method
    {
         return false;
    }
    // Continue with tests
}

onBeforeReset函数也返回false或true时,我希望测试它。
我该怎么做呢?这可能吗?
是否有一种方法可以"模拟"被测试类的某些部分?

是的,除非您想要模拟的方法是私有的或最终的,否则您只能模拟这一个方法。一个例子:

$sut = $this->getMock('Your'Class', array('onBeforeReset'));

getMock方法的第二个参数是数组,包含phpunit将模拟的方法。如果该数组为空,phpunit将模拟对象中的所有方法,但如果您精确指定了至少一个方法,phpunit将只模拟传入该数组的methodz。

你像往常一样模拟方法:

$sut->expects($this->any())
    ->method('onBeforeReset')
    ->will($this->returnValue(true));

最后你可以测试你想测试的方法:

$this->assertWhatever($expectedValue, $sut->reset());

我对单元测试的理解是测试类的公共接口。因此,在您的示例中,您只断言reset()的结果,而不是断言内部调用的所有受保护函数和私有函数。然后从reset()给出的结果推断出onbeforeereset()给出的结果。

这当然不是100%的规则。有时你真的想测试一个私有的或受保护的方法,无论出于什么原因(无论如何要考虑到这可能意味着你实际上应该重构你的代码)。

PHPUnit的创建者写了一些想法并给出了一些例子(http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html)。基本上,您使用反射使私有和受保护的方法和属性可公开访问。