PHPUnit: 如何模拟私有方法?

3
我有一个类,长这样:

class A {

    private function testing($x)
    {
        // do something
        $this->privateMethod();
    }

    private function privateMethod($number) {
        // do something
    }

}

要调用 testing() 函数,我使用以下代码:
$reflection = new \ReflectionClass('A');
$method = $reflection->getMethod('testing');
$method->setAccessible(TRUE);

$object = new A();
$parameters = array();
$result = $method->invokeArgs($object, $parameters);

但我不知道如何模拟privateMethod()。我只想测试testing()方法中的代码。我想指出我希望privateMethod()返回结果,而不实际调用该方法。


我认为您不需要测试私有方法,也不需要模拟它。您应该真正测试公共方法;其他类依赖的方法。 - Czar Pino
1
单元测试的目的是测试您的公共接口。您的私有方法应该最终在代码中的某个地方被调用,由公共/受保护的方法触发。理论上,如果您的私有方法未按预期工作,则调用代码(您正在测试的代码)将无法正常工作,因此您所做的任何断言都应该失败。 - Crackertastic
我的类包括一个公共方法和大约10个私有方法。公共方法只调用几个私有方法,实际工作由它们完成。它们中的任何一个的结果都取决于数据库中的数据。如何测试这些方法? - micobg
通常情况下,您需要模拟数据库或提供一个测试数据库来进行操作。 - Crackertastic
如果那些私有/受保护的方法可能会改变被测试方法的行为,那么您必须模拟它们以期望某些值以使测试工作正常,因此私有/受保护的方法将不会被测试单元覆盖吗? @Crackertastic - Shakir El Amrani
@ElAmraniChakir 所以,在完美的世界中,任何私有/受保护的方法都将由正在测试的公共代码调用,并处理所有未公开的代码。测试的好处之一是能够发现非公共代码如何影响公共代码的结果。这可能是代码设计上的缺陷、合法的错误,或者甚至是错误的测试。然而,模拟非公共代码以使公共代码从红色变为绿色并不是答案。 - Crackertastic
1个回答

7
如果您将private更改为protected,那么您就可以使用部分模拟来完成此操作。
$object = $this->getMockBuilder('A')
    ->setMethods(array('privateMethod'))
    ->getMock();
$object->expects($this->any())
    ->method('privateMethod')
    ->will($this->returnValue($x));

这将仅替换setMethods数组中的方法实现,所有其他方法将执行原始代码。然而,对于私有方法,这不起作用,因为模拟对象扩展了原始对象; 但是它无法覆盖private方法。


如果有人在这里寻找如何在Mockery中模拟私有方法的答案,那么答案是Mockery不支持设计上的模拟私有或受保护的方法:https://github.com/padraic/mockery/issues/30#issuecomment-1742564 - Dimitry K
它不起作用。 - afeef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接