在PHPUnit中实现给定接口的模拟对象上的未定义方法?

gre*_*emo 19 php phpunit unit-testing mocking symfony

我是单元测试和PHPUnit的新手.

我需要一个模拟,我有一个完全控制,实现ConfigurationInterface接口.测试主题是ReportEventParamConverter对象,测试必须检查我的对象和界面之间的交互.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我试图模仿界面的方式:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls);
Run Code Online (Sandbox Code Playgroud)

我需要模拟两种方法的返回值:getClass()getName().例如:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'))
;
Run Code Online (Sandbox Code Playgroud)

当我创建一个新的ReportEventParamConverter测试supports()方法时,我得到以下PHPUnit错误:

致命错误:调用未定义的方法Mock_ConfigurationInterface_21e9dccf :: getClass().

$converter = new ReportEventParamConverter();
$this->assertFalse($converter->supports($mock));
Run Code Online (Sandbox Code Playgroud)

Cyp*_*ian 19

这是因为ConfigurationInterface中没有"getClass"方法的声明.此接口中唯一的声明是方法"getAliasName".

你需要的只是告诉模拟你将使用什么方法存根:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls, array('getClass', 'getAliasName'));
Run Code Online (Sandbox Code Playgroud)

请注意,没有"getClass"声明,但您也可以存根/模拟非现有方法.因此你可以嘲笑它:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'));
Run Code Online (Sandbox Code Playgroud)

但是,除此之外,您还需要模拟"getAliasName"方法以及接口的方法或抽象方法,并且必须"实现".例如.:

$mock->expects($this->any())
   ->method('getAliasName')
   ->will($this->returnValue('SomeValue'));
Run Code Online (Sandbox Code Playgroud)

  • 你总是应该告诉你要模拟哪些方法存根/模拟.如果你没有指定,那么假设你将从类中存根所有方法(例如,如果你只指定一个方法方法A,$ mock = $ this-> getMock('Class',array('methodA') ),模拟假设你只模拟methodA,当你调用另一个方法:$ mock-> methodB(),然后执行"类"中的"真实"方法) (3认同)

Tyl*_*ier 13

塞浦路斯的答案对我有所帮助,但有一点需要注意.您可以模拟不存在的类,PHPUnit不会抱怨.所以你可以做到

$mock = $this->getMock('SomeClassThatDoesntExistOrIsMisspelledOrPerhapsYouForgotToRequire');
Run Code Online (Sandbox Code Playgroud)

这意味着如果ConfigurationInterface在运行时期间该点不存在,您仍会收到类似的消息

致命错误:调用未定义的方法Mock_ConfigurationInterface_21e9dccf :: getClass().

如果您确定该方法确实存在于该类中,则可能的问题是该类本身不存在(因为您没有要求它,或者您拼写错误,等等).


OP正在使用接口.请注意,您必须在getMock不指定要覆盖的方法列表的情况下调用,或者如果您要执行,则必须传递array()或传递所有方法名称,否则您将收到如下错误:

PHP致命错误:类Mock_HttpRequest_a7aa9ffd包含4个抽象方法,因此必须声明为抽象或实现其余方法(HttpRequest :: setOption,HttpRequest :: execute,HttpRequest :: getInfo,...)

  • 谢谢你提到这一点,这确实是一个让我遇到问题的缺课. (2认同)