我有一个名为mysqli_store_result
的类,它有一个名为TestClass
的属性。 parent
属性与parent
的类型相同。
下面显示的是我要测试的TestClass
的一部分。
TestClass
方法class TestClass
{
/**
* @param array $parentIds
* @return ApiLock[]
*/
protected function getParentLocks(array $parentIds)
{
if ($this->getParent()) {
$id = array_pop($parentIds);
return $this->getParent()->getLocks($id, $parentIds);
}
return [];
}
/**
* @param array $ids
* @return ApiLock[]
*/
protected function getLocks($id, array $ids)
{
$locks = $this->getParentLocks($ids);
if ($this->config->getLockName()) {
$locks[] = new ApiLock($this->config->getLockName() . '.' . $id, $this->config->getLockWait());
}
return $locks;
}
}
调用getLocks
方法。为了测试这个类,我模拟了getParentLocks
对象并设置为SUT的父级。类似的东西。
TestClass
但是当我运行测试时,$apiLock = $this->getMockBuilder(ApiLock::class)
->disableOriginalConstructor()
->getMock();
$parent = $this->getMockBuilder(TestClass::class)
->disableOriginalConstructor()
->getMock();
$parent->expects($this->any())
->method('getLocks')
->will($this->returnValue([$apiLock]));
$testClass->setParent($parent);
对象上的方法setLocks
将不会返回存根值,但实际上会调用父对象上的parent
方法并且测试失败。可能是我没有看到明显的东西。
应该调用存根方法而不是父对象上的实际方法。
请提前帮助我。
答案 0 :(得分:1)
问题与父子关系无关。
您应该定义要模拟的方法:
$parent = $this->getMockBuilder(TestClass::class)
->setMethods(['setLocks', 'getLocks'])
->disableOriginalConstructor()
->getMock();
将定期调用未模拟的方法,并忽略您的期望。您可能正在使用PHPUnit 4,因为在PHPUnit 5中,您会在警告中看到您为未被模拟的方法定义了期望。
更新:如果您不打电话给setMethods()
,那么所有方法都应该被嘲笑,但这仅适用于公开非抽象方法。
这是PHPUnit_Framework_MockObject_Generator中自动确定要模拟的方法的代码:
public function getClassMethods($className)
{
$class = new ReflectionClass($className);
$methods = [];
foreach ($class->getMethods() as $method) {
if ($method->isPublic() || $method->isAbstract()) {
$methods[] = $method->getName();
}
}
return $methods;
}
因此,您可以模拟受保护的方法(以及不会触发__call()
的不存在的方法),但除了公共方法之外,您需要明确指定它们。