我正在尝试测试是否在公共接口中调用受保护的方法。
<?php
abstract class SomeClassAbstract
{
abstract public foo();
public function doStuff()
{
$this->_protectedMethod();
}
protected function _protectedMethod();
{
// implementation is irrelevant
}
}
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testCalled()
{
$mock = $this->getMockForAbstractClass('SomeClass');
$mock->expects($this->once())
->method('_protectedMethod');
$mock->doStuff();
}
}
我知道它被正确调用,但PHPUnit说它从未调用过。
当我以另一种方式测试时,当方法从不调用时,会发生同样的情况:
<?php
abstract class AnotherClassAbstract
{
abstract public foo();
public function doAnotherStuff()
{
$this->_loadCache();
}
protected function _loadCache();
{
// implementation is irrelevant
}
}
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testCalled()
{
$mock = $this->getMockForAbstractClass('AnotherClass');
$mock->expects($this->once())
->method('_loadCache');
$mock->doAnotherStuff();
}
}
调用该方法,但PHPUnit表示它不是。
我做错了什么?
修改 我没有用双冒号声明我的方法,它只是表示它是一个公共方法(接口)。已更新为完整的类/方法声明。
编辑2 我应该说我在抽象类中测试一些方法实现(编辑代码以反映这一点)。由于我无法实例化该类,我该如何测试呢?
我正在考虑创建SomeClassSimple
扩展SomeClassAbstract
并对其进行测试。这是正确的做法吗?
答案 0 :(得分:11)
在我所拥有的PHPUnit版本中,类PHPUnit_Framework_MockObject_Mock
使用PHP的get_class_methods
来确定被模拟对象的接口。 get_class_methods
只会选择公共方法,而不是受保护方法或私有方法。
这符合xUnit单元测试的精神。考虑PHPUnit文档关于如何使用Mock Objects的示例。在那里,SUT是Subject
,其具有受保护的方法notify
。但是,正在测试的方法是doSomething
。将Subject
视为黑匣子,我们并不关心其实施方式的细节。但是,我们关心其行为。具体来说,我们要求在调用doSomething
时,调用任何附加观察者的update
方法。因此,我们模拟了第三方对象Observer
,并设置了将调用其update
方法的期望。请注意,尽管已执行受保护的方法notify
,但在测试中未明确命名。只要行为得以保留,这就让我们可以随时随地改变实现。
回到你的例子。
class MyTest extends PHPUnit_Framework_TestCase
{
public function testCalled()
{
$mock = $this->getMock('SomeClass');
$mock->expects($this->once())
->method('_protectedMethod');
$mock->doStuff();
}
}
这里,您的testCalled
方法不会创建被测系统(SUT)的实例,这将是SomeClass。 SomeClass的 mock 中的doStuff
版本没有做任何事情。特别是,它不会调用_protectedMethod
。
答案 1 :(得分:4)
看起来你只需告诉PHPUnit你要模拟这个函数,即:
$mock = $this->getMock('SomeClass',
array('_protectedMethod'));
$mock->expects($this->once())
->method('_protectedMethod');
$mock->doStuff();