2012-02-28 27 views
13

PHPUnit中,我们可以指定该方法通过(PHPUnit中)的任何参数被称为特别检查模拟的方法被调用,而不

->with($this->equalTo('foobar')) 

或任何

->with($this->anything()) 

参数。

但是有没有一种方法来指定该方法已被调用没有参数?

这是我希望未通过测试:

public function testZ() 
{ 
    $a = $this->getMock('q'); 

    $a->expects($this->once()) 
     ->method('z') 
     ->with(); // <--- what constraint to specify here? 

    $a->z(1); 
} 

UPD

问题具有理论性,所以我没有任何现实生活中的例子。我现在能想到的一些情况下,它可能是有用的是:

public function testMe($object) 
{ 
    $object->foo(); 
} 

而且让我们假设testMe应该(通过设计和要求)总是调用该方法不带参数(假设foo()有默认的)。因为在这种情况下,任何非默认参数(更确切地说:任何参数!=默认值,我们还不知道哪些参数可能会独立更改)会导致致命后果。

+0

+1我已经花了几分钟在github上查看PHPUnit源代码,似乎' - > with()'只能用于实际指定参数,而不禁止它们。虽然我无法真正想到验证没有通过任何参数的情况,但您需要检查一下吗?我很想知道为什么你需要验证没有发送任何参数。在没有预期的情况下传递参数不会破坏任何内容,并且当有预期的参数无法提供时,您是否可以传入NULL? – rdlowrey 2012-02-28 03:19:19

+0

@rdlowrey:增加了一个解释更新;-) – zerkms 2012-02-28 03:23:42

+0

@rdlowrey:'当你有一个无法提供的参数时,你不能只传入NULL吗?---不,你不能。方法仍然可以有可选参数 – zerkms 2012-02-28 03:25:32

回答

6

虽然rdlowrey是正确的,with()没有规定检查没有参数通过,问题不在于PHPUnit,而是PHP本身。首先,如果你的方法没有提供默认值,那么如果你不传递任何参数,解释器会引发一个致命错误。这是预料中的,并不完全与手边的问题相关,但事先声明很重要。其次,如果你的方法确实有提供了默认值,那么调用没有参数的方法将导致PHP在PHPUnit涉及到传递默认值之前改变调用。这是一个简单的测试,它演示了在PHP可以检查参数之前插入PHP本身。认识到PHP创建的模拟类具有与模拟类相同的签名(包括默认类)是关键。

class MockTest extends PHPUnit_Framework_TestCase { 
     public function test() { 
       $mock = $this->getMock('Foo', array('bar')); 
       $mock->expects($this->once()) 
        ->method('bar') 
        ->with() // does nothing, but it doesn't matter 
        ->will($this->returnArgument(0)); 
       self::assertEquals('foobar', $mock->bar()); // PHP inserts 1 and 2 
       // assertion fails because 1 != 'foobar' 
     } 
} 

class Foo { 
     public function bar($x = 1, $y = 2) { 
       return $x + $y; 
     } 
} 

这意味着你可以验证要么没有获得通过或者被传递的默认值,但不能更具体。

你能解决这个限制吗?在重写方法时,你可以从参数中移除默认值,所以你应该能够创建一个子类并对它进行模拟。这值得么?我最初的直觉反应是这是一个巨大的代码气味。无论是你的设计还是你的测试都在做错误的事情(tm)。

如果你可以提供一个真实的,具体的例子,你真的需要做这种测试,值得花一些时间来思考一个解决方案。在此之前,我对“不这样做”的纯学术回答感到满意。 :)

+0

+1表示澄清。我同意它看起来像一个代码味道...我没有看到它的真实世界的应用程序,它似乎是一个简单的重构可以避免的问题。 – rdlowrey 2012-02-28 13:42:01

+0

“在此之前,我对”不这样做“的纯粹学术回答感到满意。”:)我同意我不能想到现实世界的例子,这就是为什么我说“这个问题有理论性“ - 所以我只问了理论上的可能性,没有解释为什么我需要这样做;-) – zerkms 2012-02-28 19:21:08

+0

但仍然想知道如何嘲弄 – zerkms 2012-02-28 19:21:37

4

PHPUnit模拟对象只能使用->with()约束方法来验证传递参数的计数值或相应值是否与调用时传递给模拟方法的值相匹配。你不能用它来要求没有参数被传递给模拟方法。

模拟验证过程特别检查传递的参数数量和相关值是否与传递给约束条件的数据兼容。此外,正如您可能已经看到的,指定没有任何值的with约束也不起作用;如果with未收到任何参数,则不会添加任何验证参数约束。

您可以看到实际的PHPUnit_Framework_MockObject_Matcher_Parameters::verify方法用于验证链接的github源中的模拟方法参数。

如果验证未传递参数是一项要求,则需要指定您自己的模拟类来验证PHPUnit模拟功能之外的这种情况。

+0

没有编辑这个答案我想补充一点,我已经得出了这个结论,而不是从PHPUnit内部的一个不可思议的细微的理解,而是从很长一段时间搜索相关的源代码,试图完成问题的既定目标。我相信链接的源代码证明这是不可能的,但如果有人能找到一种方法使其工作,请分享。 – rdlowrey 2012-02-28 04:15:55

相关问题