PHPUnit模拟抽象类的所有方法

6
我有一个PHPUnit测试用例,直接继承自PHPUnit_Framework_TestCase。在这个类的一个测试中,我需要获取某个服务对象的模拟。这个服务对象是由一个抽象基类定义的类型。这个基类包含具体和抽象方法。我想获取整个东西的完整模拟(即所有方法都被模拟出来)。我的问题是如何做到这一点。
->getMock会报错,因为只有具体的方法被模拟出来,而抽象的方法没有被模拟出来。
->getMockForAbstractClass模拟了抽象方法,但没有模拟具体方法。
如何将它们全部模拟出来?
(我正在使用PHPUnit 3.7.13)

1
这已经在后续版本的PHPUnit中实现,正如此答案所提到的。https://dev59.com/VGsz5IYBdhLWcg3wOlOh#13365088 - Schleis
3个回答

6

只需调用->getMock('Class');即可模拟对象上的所有方法并实现所有抽象方法。

我不太确定你哪里出了问题,但由于它似乎很简单,我写了一个示例。

如果对您不起作用,我需要一个重现您尝试做什么的案例。

示例

<?php

class mockTest extends PHPUnit_Framework_TestCase {

    // Without expectations
    public function testMocking() {
        $x = $this->getMock('MockMe');
        $this->assertNull($x->foo());
        $this->assertNull($x->bar());
    }

    // With expectations
    public function testMocking2() {
        $x = $this->getMock('MockMe');
        $x->expects($this->once())->method('foo')->will($this->returnValue(true));
        $x->expects($this->once())->method('bar')->will($this->returnValue(true));
        $this->assertTrue($x->foo());
        $this->assertTrue($x->bar());
    }

}

abstract class MockMe {

    abstract public function foo();

    public function bar() {
        return 1 + $this->foo();
    }

}

产生的结果

PHPUnit 3.7.13 by Sebastian Bergmann.

..

Time: 0 seconds, Memory: 6.25Mb

OK (2 tests, 5 assertions)

3
我正在使用 $this->getMock('SomeAbstractClass')。出现以下错误:致命错误:类 Mock_SomeAbstractClass_cbc14c8a 包含 2 个抽象方法,因此必须声明为抽象或者实现剩余的方法 (SomeAbstractClass::foo, SomeAbstractClass::bar)。位于 /usr/share/php/PHPUnit/Framework/MockObject/Generator.php(231) : eval()'d code 的第 3302 行。 - Jeroen De Dauw
有趣的是,你提供的示例代码在我的环境下可以很好地运行。我的抽象类相当复杂,并实现了一些接口。也许这会在 PHPUnit 中引发某些错误?我目前的解决方法是在 getMock 方法调用中只引用其一个衍生类。 - Jeroen De Dauw
当然总是有可能的。或者它找不到/加载其中一个接口,并且无法提前确定方法(或其他什么!)。如果您可以使用可以共享的代码重现错误,那么肯定会欢迎提交错误报告 :) - edorian

4

如果一个抽象类的方法不是公共的,那么 $this->getMock(...) 看起来会失败。

如果你不想使用派生类,你可以在测试基类中添加以下内容:

protected function getMockOfAbstractClass($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) {
    if ($methods !== null) {
        $methods = array_unique(array_merge($methods,
        $this->getMethods($originalClassName, $callAutoload)));
    }
    return parent::getMock($originalClassName, $methods, $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload);
}

private function getMethods($class, $autoload=true) {
    $methods = array();
    if (class_exists($class, $autoload) || interface_exists($class, $autoload)) {
        $reflector = new ReflectionClass($class);
        foreach ($reflector->getMethods( ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_ABSTRACT ) as $method) {
            $methods[] = $method->getName();
        }
    }
    return $methods;
}

这是从以下链接改编而来:PHPUnit中如何模拟抽象类中的具体方法

0

使用getMockForAbstractClass时,默认情况下不会模拟具体方法。要模拟具体方法,请使用第七个参数($mockedMethods)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接