PHPUnit Stubbing类方法声明为"final"

rr.*_*rr. 15 php phpunit unit-testing mocking

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

例:

要被嘲笑的阶级

class Class_To_Mock
{
    final public function needsToBeCalled($options)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试用例

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'));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

例:

要被嘲笑的阶级

class Class_To_Mock
{
    final public function needsToBeCalled($options)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

嘲笑

class Class_To_MockMock
{
    public function needsToBeCalled($options)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

要测试的课程

class Class_To_Be_Tested
{
    public function setClassToMock(Class_To_Mock $classToMock)
    {
        ...
    }

    public function getClassToMock()
    {
        ...
    }

    public function doSomething()
    {
        $this->getClassToMock()
             ->needsToBeCalled(array('option'));
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试用例

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Mik*_*e B 14

我不认为PHPUnit支持最终方法的存根/模拟.您可能必须为此情况创建自己的存根并执行一些扩展技巧:

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

第11章的PHPUnit手册中找到了这个.测试双打

限制

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


hid*_*dro 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'));
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)