当我使用PHPUnit对我的PHP代码进行单元测试时,我试图找出模拟对象的正确方法,而不会嘲笑它的任何方法。
问题是如果我不调用getMockBuilder()->setMethods()
,那么对象上的所有方法都将被模拟,我无法调用我想要测试的方法;但如果我做调用setMethods()
,那么我需要告诉它要模拟哪种方法,但我不想模拟任何方法。但我需要创建模拟,这样我就可以避免在测试中调用构造函数。
以下是我想要测试的方法的一个简单示例:
class Foobar
{
public function __construct()
{
// stuff happens here ...
}
public function myMethod($s)
{
// I want to test this
return (strlen($s) > 3);
}
}
我可以使用以下方式测试myMethod()
$obj = new Foobar();
$this->assertTrue($obj->myMethod('abcd'));
但这会叫Foobar的构造函数,我不想要它。所以相反,我会尝试:
$obj = $this->getMockBuilder('Foobar')->disableOriginalConstructor()->getMock();
$this->assertTrue($obj->myMethod('abcd'));
但是在不使用getMockBuilder()
的情况下调用setMethods()
将导致其所有方法被模拟并返回null,因此我对myMethod()
的调用将返回null而不触及我打算测试的代码
到目前为止我的解决方法是:
$obj = $this->getMockBuilder('Foobar')->setMethods(array('none'))
->disableOriginalConstructor()->getMock();
$this->assertTrue($obj->myMethod('abcd'));
这将模拟名为'none'的方法,该方法不存在,但PHPUnit并不关心。它会让myMethod()取消模拟,以便我可以调用它,它也会让我禁用构造函数,这样我就不会调用它。完善!除了必须指定一个不存在的方法名称 - “无”,“blargh”或“xyzzy”似乎作弊。
这样做的正确方法是什么?
答案 0 :(得分:45)
您可以将null
传递给setMethods()
,以避免模仿任何方法。传递一个空数组将模拟所有方法。后者是您找到的方法的默认值。
话虽如此,我想说这样做的必要性可能会指出这个类的设计存在缺陷。这种方法应该是静态的还是移到另一个类?如果该方法不需要完全构造的实例,则表明它可能是一个可以变为静态的实用方法。
答案 1 :(得分:3)
另一个简洁而又简洁的解决方案就是将魔术构造函数列为模拟方法之一:
$mock = $this->getMock('MyClass', array('__construct'));
答案 2 :(得分:0)
或者您可以直接使用getMock()
。
$mock = $this->getMock('MyClass', null, array(), null, false);
答案 3 :(得分:0)
如果有任何方法,例如可以通过entityManager调用它,您可以使用它:
$this->entityManager
->expects($this->any())
->method($this->anything())
->willReturn($repository);
答案 4 :(得分:-8)
这对我有用:
$this->getMock($class, array(), array(), '', false);