PHPUnit调用未定义的方法`Mock_x _ :: method()`

时间:2015-06-16 05:05:15

标签: php mocking phpunit undefined

我试图创建我的第一个phpunit测试,发现自己需要在IMailer接口上存根方法。

interface IMailer
{
    public function send($to, $from, $cc, $subject, $body);
    public function sent();
}

    $mailer = $this->getMockBuilder(
        'IMailer',
        array('send', 'sent'))->getMock();

    $mailer->method('send')->willRreturn(0);

然而,我一直在

PHP Fatal error: 
  Call to undefined method Mock_Mailer_13fc0a04::method()
  in ...Test.php on line 16

var_dump($mailer);导致

class Mock_IMailer_4c3e02a7#215 (1) {
  private $__phpunit_invocationMocker =>
  NULL
}

使用expect($this->any())会出现dito错误 - 似乎被模拟的对象没有任何模拟功能......

我在ubuntu盒子上运行phpunit 3.7.28和php 5.5.9。

为什么?我该如何解决?

2 个答案:

答案 0 :(得分:5)

getMockBuilder函数仅接受className作为参数。初始化模拟对象方法的正确方法是使用setMethods函数(参见phpunit docs

   $mailer = $this->getMockBuilder('IMailer')
       ->setMethods(array('send', 'sent'))
       ->getMock();

此外,您可能希望在使用模拟对象时也有一些预期定义:

   $mailer->expects($this->any())
        ->method('send')
        ->willReturn(0);

修改

以上适用于较新的phpunit版本。对于phpunit 3.7.28,模拟对象的使用有点不同(即期望似乎是强制性的,而且还没有返回)。对于3.7.28版本,您应将第二部分修改为:

   $mailer->expects($this->any())
        ->method('send')
        ->will($this->returnValue(0));

我建议更新到以后的phpunit版本,因为在这个旧版本中找到文档似乎有些困难。

答案 1 :(得分:0)

对于仍在使用旧版本的PHPUnit但仍希望能够直接调用method()的任何人来说,替代解决方案是覆盖默认的模拟对象类模板。

复制MockObject/Generator/mocked_class.tpl.dist,并将副本命名为mocked_class.tpl。然后,只需将the code for the method() method添加到模板中:

public function method()
{
    $any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
    $expects = $this->expects($any);
    $args = func_get_args();
    return call_user_func_array(array($expects, 'method'), $args);
}

这样您就可以直接致电$mock->method()了。但是,您仍需要使用->will($this->returnValue(0))而不是->willReturn(0)。为此,您需要引入自定义调用构建器和调用模拟器:

class My_MockObject_Builder_InvocationMocker
    extends PHPUnit_Framework_MockObject_Builder_InvocationMocker {

    public function willReturn( $value ) {
        return $this->will( new PHPUnit_Framework_MockObject_Stub_Return( $value ) );
    }
}

class My_MockObject_InvocationMocker
    extends PHPUnit_Framework_MockObject_InvocationMocker {

    public function expects( PHPUnit_Framework_MockObject_Matcher_Invocation $matcher ) {
        return new My_MockObject_Builder_InvocationMocker($this, $matcher);
    }
}

再次更新您的模板,使用My_MockObject_InvocationMocker代替PHPUnit_Framework_MockObject_InvocationMocker

完整的模板将如下所示:

{prologue}{class_declaration}
{
    protected static $staticInvocationMocker;
    protected $invocationMocker;

{clone}{mocked_methods}
    public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
    {
        return $this->__phpunit_getInvocationMocker()->expects($matcher);
    }

    public function method()
    {
        $any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
        $expects = $this->expects($any);
        $args = func_get_args();
        return call_user_func_array(array($expects, 'method'), $args );
    }

    public static function staticExpects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
    {
        return self::__phpunit_getStaticInvocationMocker()->expects($matcher);
    }

    public function __phpunit_getInvocationMocker()
    {
        if ($this->invocationMocker === NULL) {
            $this->invocationMocker = new My_MockObject_InvocationMocker;
        }

        return $this->invocationMocker;
    }

    public static function __phpunit_getStaticInvocationMocker()
    {
        if (self::$staticInvocationMocker === NULL) {
            self::$staticInvocationMocker = new My_MockObject_InvocationMocker;
        }

        return self::$staticInvocationMocker;
    }

    public function __phpunit_hasMatchers()
    {
        return self::__phpunit_getStaticInvocationMocker()->hasMatchers() ||
               $this->__phpunit_getInvocationMocker()->hasMatchers();
    }

    public function __phpunit_verify()
    {
        self::__phpunit_getStaticInvocationMocker()->verify();
        $this->__phpunit_getInvocationMocker()->verify();
    }

    public function __phpunit_cleanup()
    {
        self::$staticInvocationMocker = NULL;
        $this->invocationMocker       = NULL;
    }
}{epilogue}