PHPUnit Stubbing类方法声明为“final”

时间:2010-06-20 16:13:13

标签: php unit-testing mocking phpunit

我正在为一个类方法编写单元测试,该方法使用mock调用另一个类的方法,只需要调用的方法被声明为final,因此PHPUnit无法模拟它。我可以采取不同的方法吗?

示例:

要被嘲笑的课

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'));
    }
}

编辑:如果使用Mike B提供的解决方案,你有一个setter / getter用于你正在模拟的对象进行类型检查(为了确保将正确的对象传递给setter),你需要模拟你正在测试的类中的getter,让它返回另一个mock。

示例:

要被嘲笑的课

class Class_To_Mock
{
    final public function needsToBeCalled($options)
    {
        ...
    }
}

模拟

class Class_To_MockMock
{
    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()
    {
        $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();
    }
}

2 个答案:

答案 0 :(得分:14)

我不认为PHPUnit支持最终方法的存根/模拟。你可能必须为这种情况创建自己的存根并做一些扩展技巧:

class myTestClassMock {
  public function needsToBeCalled() {
    $foo = new Class_To_Mock();
    $result = $foo->needsToBeCalled();
    return array('option');
  }
}

Chapter 11. Test Doubles

下的PHPUnit手册中找到了这个
  

<强>限制

     

请注意,无法对最终,私有和静态方法进行存根或模拟。它们被PHPUnit的测试双重功能忽略,并保留其原始行为。

答案 1 :(得分:5)

我今天偶然发现了这个问题。另一种方法是模拟类实现的接口,假设它实现了一个接口,并将接口用作类型提示。

例如,考虑到问题,您可以创建一个界面并按如下方式使用它:

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'));
        ...
    }
}