PHPUnit stubing类方法声明为;“最后的”;
我正在为一个类方法编写一个单元测试,该类方法使用mock调用另一个类的方法,只有需要调用的方法被声明为final,因此PHPUnit无法对其进行模拟。我可以采取不同的方法吗 例如: 要嘲笑的类PHPUnit stubing类方法声明为;“最后的”;,php,unit-testing,mocking,phpunit,Php,Unit Testing,Mocking,Phpunit,我正在为一个类方法编写一个单元测试,该类方法使用mock调用另一个类的方法,只有需要调用的方法被声明为final,因此PHPUnit无法对其进行模拟。我可以采取不同的方法吗 例如: 要嘲笑的类 class Class_To_Mock { final public function needsToBeCalled($options) { ... } } class Class_To_Mock { final public function need
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
我的测试用例
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$mock = $this->getMock('Class_To_Mock', array('needsToBeCalled'));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
}
}
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$classToTest = $this->getMock('Class_To_Be_Tested', array('getClassToMock'));
$mock = $this->getMock('Class_To_MockMock', array('needsToBeCalled'));
$classToTest->expects($this->any())
->method('getClassToMock')
->will($this->returnValue($mock));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
$classToTest->doSomething();
}
}
编辑:如果使用Mike B提供的解决方案,并且您要模拟的对象有一个执行类型检查的setter/getter(以确保将正确的对象传递到setter),那么您需要模拟您要测试的类上的getter,并让它返回另一个mock 例如: 要嘲笑的类
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
class Class_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
嘲弄
待测类别
class Class_To_Be_Tested
{
public function setClassToMock(Class_To_Mock $classToMock)
{
...
}
public function getClassToMock()
{
...
}
public function doSomething()
{
$this->getClassToMock()
->needsToBeCalled(array('option'));
}
}
我的测试用例
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$mock = $this->getMock('Class_To_Mock', array('needsToBeCalled'));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
}
}
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$classToTest = $this->getMock('Class_To_Be_Tested', array('getClassToMock'));
$mock = $this->getMock('Class_To_MockMock', array('needsToBeCalled'));
$classToTest->expects($this->any())
->method('getClassToMock')
->will($this->returnValue($mock));
$mock->expects($this->once())
->method('needsToBeCalled')
->with($this->equalTo(array('option'));
$classToTest->doSomething();
}
}
我认为PHPUnit不支持对final方法进行存根/模拟。在这种情况下,您可能需要创建自己的存根,并进行一些扩展技巧:
class myTestClassMock {
public function needsToBeCalled() {
$foo = new Class_To_Mock();
$result = $foo->needsToBeCalled();
return array('option');
}
}
在PHPUnit手册的
限制
请注意,final、private和static方法不能被存根或模拟。它们被PHPUnit的双重测试功能忽略,并保留其原始行为
我今天偶然发现了这个问题。另一种方法是模拟类实现的接口,因为它实现了一个接口,并且您将该接口用作类型提示 例如,考虑到问题,您可以创建一个接口并按如下方式使用它:
interface Interface_To_Mock
{
function needsToBeCalled($options);
}
class Class_To_Mock implements Interface_To_Mock
{
final public function needsToBeCalled($options)
{
...
}
}
class Class_To_Be_Tested
{
public function setClassToMock(Interface_To_Mock $classToMock)
{
...
}
...
}
class MyTest extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
$mock = $this->getMock('Interface_To_Mock', array('needsToBeCalled'));
...
}
}
如果您正在测试的类依赖于对被模拟的类/方法进行类型检查的getter/setter,那么还需要额外的步骤。我把这个添加到原来的文章中。@ RR请考虑把这个作为答案,而不是把这个问题放在一个问题上。我直接回答了最初的问题。如果OP编辑了他的问题,我没有义务继续更新我的答案以匹配这个问题的移动目标。而且,这些内容已经有3年多的历史了,平均每天点击率不到一次。所以最原始的问题和答案没有那么有趣。不要嘲笑最后的方法。。不要引入模拟最终方法的变通方法,您的代码将更干净。@MikeB当然您没有义务做任何事情。我只是建议把这整条线清理干净。我不是PHP专家,所以我没有深入研究细节。如果您的答案仍然有效,则OP问题的解决方案部分应移至另一个答案。@MikeB我同意
不要模仿最终方法。。不要引入模拟最终方法的变通方法,您的代码将更干净
,问题是旧的遗留代码迫使您这样做:'(