PHPUnit Stubbing 类方法声明为“final”

2022-08-30 23:29:14

我正在为一个类方法编写一个单元测试,该方法使用模拟调用另一个类的方法,只有需要调用的方法被声明为 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();
    }
}

答案 1

我不认为PHPUnit支持最终方法的存根/嘲笑。您可能需要为这种情况创建自己的存根,并执行一些扩展技巧:

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

在第11章的PHPUnit手册中找到了这一点。双打测试

局限性

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


答案 2

我今天偶然发现了这个问题。另一种方法是模拟类实现的接口,前提是它实现了一个接口,并且您使用该接口作为类型提示。

例如,给定有问题的问题,您可以创建一个接口并按如下方式使用它:

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

推荐