我正在尝试创建我的第一个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
a 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。
怎么来了? 我该如何解决它?
getMockBuilder函数只接受className作为参数。初始化模拟对象方法的正确方法是使用 setMethods 函数(参见 phpunit 文档)
$mailer = $this->getMockBuilder('IMailer')
->setMethods(array('send', 'sent'))
->getMock();
此外,当您使用模拟对象时,您可能还希望有一些期望的定义:
$mailer->expects($this->any())
->method('send')
->willReturn(0);
编辑
上述情况适用于较新的phpunit版本。对于 phpunit 3.7.28,模拟对象的用法略有不同(即期望似乎是强制性的,并且 willReturn 尚不可用)。对于 3.7.28 版本,您应该将第二部分修改为:
$mailer->expects($this->any())
->method('send')
->will($this->returnValue(0));
我建议更新到以后的phpunit版本,因为似乎很难找到这个旧版本的文档。
对于仍在使用旧版本的 PHPUnit,但仍希望能够直接调用method()
的任何人,另一种解决方案是覆盖默认的模拟对象类模板。
复制MockObject/Generator/mocked_class.tpl.dist
,并将副本命名为mocked_class.tpl
。然后,只需将 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}