php 在 PHPUnit 中实现给定接口的模拟对象的未定义方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12599957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Undefined method on mock object implementing a given interface in PHPUnit?
提问by gremo
I'm new to unit testing and PHPUnit.
我是单元测试和 PHPUnit 的新手。
I need a mock, on which I have a full control, implementing ConfigurationInterfaceinterface. Test subject is ReportEventParamConverterobject and test must check the interaction between my object and the interface.
我需要一个模拟,我可以完全控制它,实现ConfigurationInterface接口。测试主题是ReportEventParamConverter对象,测试必须检查我的对象和界面之间的交互。
ReportEventParamConverterobject (here simplified):
ReportEventParamConverter对象(此处简化):
class ReportEventParamConverter implements ParamConverterInterface
{
/**
* @param Request $request
* @param ConfigurationInterface $configuration
*/
function apply(Request $request, ConfigurationInterface $configuration)
{
$request->attributes->set($configuration->getName(), $reportEvent);
}
/**
* @param ConfigurationInterface $configuration
* @return bool
*/
function supports(ConfigurationInterface $configuration)
{
return 'My\Namespaced\Class' === $configuration->getClass();
}
}
And this is the way I'm trying to mock the interface:
这就是我试图模拟界面的方式:
$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls);
I need to simulate the returned values for two methods: getClass()and getName(). For example:
我需要模拟两种方法的返回值:getClass()和getName()。例如:
$mock->expects($this->any())
->method('getClass')
->will($this->returnValue('Some\Other\Class'))
;
When i create a new ReportEventParamConverterand test supports()method, i get the following PHPUnit error:
当我创建一个新的ReportEventParamConverter测试supports()方法时,我收到以下 PHPUnit 错误:
Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().
致命错误:调用未定义的方法 Mock_ConfigurationInterface_21e9dccf::getClass()。
$converter = new ReportEventParamConverter();
$this->assertFalse($converter->supports($mock));
采纳答案by Cyprian
It's because there is no declaration of "getClass" method in ConfigurationInterface. The only declaration in this interface is method "getAliasName".
这是因为 ConfigurationInterface 中没有“getClass”方法的声明。此接口中唯一的声明是方法“getAliasName”。
All you need is to tell the mock what methods you will be stubing:
你所需要的只是告诉模拟你将存根什么方法:
$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($cls, array('getClass', 'getAliasName'));
Notice that there is no "getClass" declaration but you can stub/mock non existing method as well. Therefor you can mock it:
请注意,没有“getClass”声明,但您也可以存根/模拟不存在的方法。因此你可以嘲笑它:
$mock->expects($this->any())
->method('getClass')
->will($this->returnValue('Some\Other\Class'));
But in addtion you need to mock "getAliasName" method as well as long as it's interface's method or abstract one and it has to be "implemented". Eg.:
但此外,您需要模拟“getAliasName”方法,只要它是接口的方法或抽象方法,并且必须“实现”。例如。:
$mock->expects($this->any())
->method('getAliasName')
->will($this->returnValue('SomeValue'));
回答by Tyler Collier
Cyprian's answer helped me, but there's a gotcha to be aware of. You can mock classes that don't exist, and PHPUnit won't complain. So you could do
Cyprian 的回答对我有帮助,但有一个问题需要注意。您可以模拟不存在的类,PHPUnit 不会抱怨。所以你可以这样做
$mock = $this->getMock('SomeClassThatDoesntExistOrIsMisspelledOrPerhapsYouForgotToRequire');
This means that if ConfigurationInterfacedoesn't exist at that point during runtime, you'll still get a message like
这意味着如果ConfigurationInterface在运行时的那个点不存在,你仍然会收到类似的消息
Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().
致命错误:调用未定义的方法 Mock_ConfigurationInterface_21e9dccf::getClass()。
If you're sure the method really exists on the class, then the likely problem is the class itself doesn't exist (because you haven't required it, or you misspelled it, etc).
如果您确定该方法确实存在于该类中,那么可能的问题是该类本身不存在(因为您不需要它,或者您拼错了它,等等)。
The OP is using an interface. Be advised that you must call getMockwithout specifying the list of methods to override, or if you do, you must either pass array(), or pass ALL the method names, or you'll get an error like the following:
OP 正在使用接口。请注意,您必须在getMock不指定要覆盖的方法列表的情况下调用,否则,您必须传递array()或传递所有方法名称,否则您将收到如下错误:
PHP Fatal error: Class Mock_HttpRequest_a7aa9ffd contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (HttpRequest::setOption, HttpRequest::execute, HttpRequest::getInfo, ...)
PHP 致命错误:Mock_HttpRequest_a7aa9ffd 类包含 4 个抽象方法,因此必须声明为抽象方法或实现其余方法(HttpRequest::setOption、HttpRequest::execute、HttpRequest::getInfo、...)
回答by chx
Tyler Collier's warning is fair but doesn't contain a code snippet on how to code around it. Note this is very nasty and you should fix the interface instead. With that warning added:
Tyler Collier 的警告是公平的,但没有包含关于如何围绕它编码的代码片段。请注意,这是非常讨厌的,您应该修复接口。添加了该警告:
$methods = array_map(function (\ReflectionMethod $m) { return $m->getName();}, (new \ReflectionClass($interface))->getMethods());
$methods[] = $missing_method;
$mock = $this->getMock($interface, $methods);

