为什么 PHPUnit 在模拟不存在的方法时默默地不返回任何内容


Why does PHPUnit silently return nothing when mocking non-existent methods?

我花了一些时间调试对象测试,却发现 PHPUnit 静默地忽略了指定的存根行为,因为该方法尚未在正在存根的类中定义:

<?php
class SomeClass {
    public function aMethod() 
    {
    // exists, but no body;
    }
}
class someOtherClassTest extends 'PHPUnit_Framework_TestCase
{
    public function testSomeDependentClassMethod()
    {
        $stub = $this->getMock('SomeClass');
        $stub->expects($this->once())
             ->method('aFakeMethod')
             ->will($this->returnValue('foo'));
        // silently returns nothing!
        $stub->aFakeMethod();
        $stub->expects($this->once())
             ->method('aMethod')
             ->will($this->returnValue('bar'));
        // as expected, returns 'bar'
        $stub->aMethod();
    }
}

这是故意的吗?如果是这样,背后的原因是什么?

我在文档中找不到有关此行为的任何内容,但如果打算以这种方式工作,则不想将其报告为错误。

这是一个悬而未决的问题,请参阅以下 GitHub 链接:

https://github.com/sebastianbergmann/phpunit-mock-objects/issues/21

https://github.com/sebastianbergmann/phpunit-mock-objects/issues/12

当你得到模拟方法时,PHPUnit 通过反射获取类的方法,并将这些方法添加到模拟中。 除非您向模拟提供要模拟的方法列表,否则它将使用这些方法并保留其他所有内容。

https://github.com/sebastianbergmann/phpunit-mock-objects/blob/master/src/Framework/MockObject/Generator.php#L741

如果您阻止使用自动加载器加载类,也会发生这种情况。 在这种情况下,不会替换任何方法。

为您的模拟提供您将要模拟的方法列表,这是getMock()方法的第二个参数。 然后,您将能够存根不存在的方法。 因此,请将测试更改为:

public function testSomeDependentClassMethod()
    {
        $stub = $this->getMock('SomeClass', ['aFakeMethod', 'aMethod']);
        $stub->expects($this->once())
             ->method('aFakeMethod')
             ->will($this->returnValue('foo'));
        $stub->aFakeMethod();
        $stub->expects($this->once())
             ->method('aMethod')
             ->will($this->returnValue('bar'));
        $stub->aMethod();
    }

或者你可以使用getMockBuilder:

public function testSomeDependentClassMethod()
    {
        $stub = $this->getMockBuilder('SomeClass')
                     ->setMethods(['aFakeMethod', 'aMethod'])
                     ->getMock()
        $stub->expects($this->once())
             ->method('aFakeMethod')
             ->will($this->returnValue('foo'));
        $stub->aFakeMethod();
        $stub->expects($this->once())
             ->method('aMethod')
             ->will($this->returnValue('bar'));
        $stub->aMethod();
    }