PHPUnit Mock - 方法不存在。

19

我最近将一个基于CakePhp 3.x的应用程序中的IntegrationTestCase中的PHPunit从5.3更新到5.5,但我不知道如何更新我的模拟生成脚本。

最初我是这样创建我的模拟对象的:

$stub = $this->getMock('SomeClass', array('execute'));
$stub->method('execute')
     ->will($this->returnValue($this->returnUrl));

在将 PHPUnit 升级至 5.5 后,我收到了以下警告:

PHPUnit_Framework_TestCase::getMock() is deprecated,
use PHPUnit_Framework_TestCase::createMock()
or PHPUnit_Framework_TestCase::getMockBuilder() instead

为了解决这个警告,我将模拟生成更改为:

$stub = $this->getMockBuilder('SomeClass', array('execute'))->getMock();
$stub->method('execute')
     ->will($this->returnValue($this->returnUrl));```

现在在运行测试时,我遇到了以下错误信息:

exception 'PHPUnit_Framework_MockObject_RuntimeException' 
with message 'Trying to configure method "execute" which cannot be
configured because it does not exist, has not been specified, 
is final, or is static'
任何人知道如何避免这个错误吗?谢谢。

你能发布 execute 方法的代码吗? - Matteo
5个回答

37

PHPUnit_Framework_TestCase::getMockBuilder()只接受一个参数,即类名称。要模拟的方法应通过返回的模拟构建器对象的setMethods()方法定义。

$stub = $this
    ->getMockBuilder('SomeClass')
    ->setMethods(['execute'])
    ->getMock();

另请参见


谢谢,就这样了。我应该使用setMethods而不是尝试将方法名数组作为第二个参数传递给getMockBuilder()方法。 - David Albrecht
1
FYI,setMethods()已被弃用,应该替换为onlyMethods()。 - GordonM
@GordonM 没错,但是CakePHP 3.x默认需要最新的PHPUnit 6.x,其中onlyMethods()还不存在。我不确定3.x是否与PhpUnit 8+兼容。 - ndm

21

当我再次遇到这个问题时,我将把它作为我的答案留下来:

模拟的方法可能不是私有的。


2
首先,这只是一个

开始标签。

$stub = $this->getMockBuilder('SomeClass')->getMock();

其次,错误提示表明在您的类SomeClass中不存在execute方法。

因此,请检查该方法是否真实存在且为public而非final

如果一切正常,请检查完整的类名是否真实存在并指定了正确的命名空间。

为避免类名的愚蠢错误,最好使用以下语法:

$stub = $this->getMockBuilder(SomeClass::class)->getMock();

在这种情况下,如果SomeClass不存在或命名空间缺失,你将会清晰地收到一个关于此的错误提示。

谢谢,问题在于我没有使用setMethods()函数(请参见ndm的答案)。 - David Albrecht
这不是必需的步骤。你原来的类中有这个方法吗? - Dmitry Malyshenko
如果该方法不是公共的,则需要这样做。 - ndm
我知道在一个理想的世界里,你只需要测试公共API :) - ndm
我想说的是,如果方法存在且为公共方法,则不需要setMethods,否则根本没有必要创建模拟对象。 - Dmitry Malyshenko
显示剩余9条评论

2

除了上面的信息之外:分离模拟方法声明

不要这样做:

$mock
    ->method('persist')
       ->with($this->isInstanceOf(Bucket::class))
       ->willReturnSelf()
    ->method('save')
       ->willReturnSelf()
;

请使用以下代码:
$mock
    ->method('persist')
        ->willReturnSelf()
;

$mock
   ->method('save')
       ->willReturnSelf()
;

1
也许,在您模拟的类中不存在该方法。

该方法在模拟对象中缺失(请参考ndm的接受答案和我的评论以获取解决方案)。 - David Albrecht
我曾经遇到过同样的问题,后来发现我的类中没有这个方法,所以我提出了这个解决方案来解决同样的问题。 - Yassine CHABLI
明白了,可能会帮助其他人。 - David Albrecht

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