【问题标题】:Mock an internal function call of current class under test模拟当前被测类的内部函数调用
【发布时间】:2013-06-04 11:11:18
【问题描述】:

我想测试一下这个功能:

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

    // Continue with tests
}

我也希望在onBeforeReset 函数返回 false 或 true 时对其进行测试。
我怎样才能做到这一点?这可能吗?
有没有办法“模拟”被测类的某些部分?

【问题讨论】:

  • 您正在测试返回值是否为真/假。你想测试同样的东西是什么意思?
  • 我想在onBeforeReset返回true和onBeforeReset返回false时测试reset函数。
  • 如果//continue with tests部分代码可能返回false,您可能希望返回一个带有键的数组(例如['onBeforeReset'])作为onBeforeReset()的返回值另一个用于reset()。最后,您可以测试该特定键是否存在/设置... .

标签: php phpunit php-5.3


【解决方案1】:

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

$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());

【讨论】:

  • 嗯...这很有趣。我已经使用了模拟,但我没有考虑模拟当前测试的一部分。但是,我的对象是使用 getInstance 工厂方法返回的,对此有何建议?
  • 你总是可以模拟“getInstance”来返回你的$sut。但绝对更好的方法是直接构建对象。但还要注意一件事——你的受保护方法“onBeforeReset”也应该被测试!并且私有/受保护的方法应该通过公共接口进行测试,所以实际上您可能根本不想要模拟“重置”方法?想想看:)
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 2015-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多