2010-07-29 22 views
35

我遇到了PHPUnit模擬對象的一個​​奇怪問題。我有一個應該被調用兩次的方法,所以我使用「at」匹配器。這是第一次調用該方法,但由於某種原因,第二次調用該方法時,我得到「Mocked方法不存在」。我之前使用過「at」匹配器,並且從未遇到過這種情況。

我的代碼看起來是這樣的:

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    ... 

    public function testThis() 
    { 
     $mock = $this->getMock('MyClass', array('exists', 'another_method', '...')); 
     $mock->expects($this->at(0)) 
      ->method('exists') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue(true)); 

     $mock->expects($this->at(1)) 
      ->method('exists') 
      ->with($this->equalTo('bar')) 
      ->will($this->returnValue(false)); 
    } 

    ... 
} 

當我運行測試,我得到:

Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1. 
Mocked method does not exist. 

如果我刪除了第二匹配,我沒有得到這個錯誤。

有沒有人遇到過這個?

謝謝!

回答

37

這個問題最終與我如何理解「在」匹配器工作。另外,我的例子並不像我的單元測試那樣是逐字的。我認爲「at」匹配器計數器在每個查詢的基礎上工作,它在每個對象實例的基礎上真正工作。

例子:

class MyClass { 

    public function exists($foo) { 
     return false; 
    } 

    public function find($foo) { 
     return $foo; 
    } 
} 

錯誤:

class MyTest extends PHPUnit_Framework_TestCase 
{ 

    public function testThis() 
    { 
     $mock = $this->getMock('MyClass'); 
     $mock->expects($this->at(0)) 
      ->method('exists') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue(true)); 

     $mock->expects($this->at(0)) 
      ->method('find') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue('foo')); 

     $mock->expects($this->at(1)) 
      ->method('exists') 
      ->with($this->equalTo('bar')) 
      ->will($this->returnValue(false)); 

     $this->assertTrue($mock->exists("foo")); 
     $this->assertEquals('foo', $mock->find('foo')); 
     $this->assertFalse($mock->exists("bar")); 
    } 

} 

正確:

class MyTest extends PHPUnit_Framework_TestCase 
{ 

    public function testThis() 
    { 
     $mock = $this->getMock('MyClass'); 
     $mock->expects($this->at(0)) 
      ->method('exists') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue(true)); 

     $mock->expects($this->at(1)) 
      ->method('find') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue('foo')); 

     $mock->expects($this->at(2)) 
      ->method('exists') 
      ->with($this->equalTo('bar')) 
      ->will($this->returnValue(false)); 

     $this->assertTrue($mock->exists("foo")); 
     $this->assertEquals('foo', $mock->find('foo')); 
     $this->assertFalse($mock->exists("bar")); 
    } 

} 
+5

是的,但我認爲這是PHPUnit中的錯誤。該文件說: 返回,當它評估的方法在特定的$ index上被調用匹配的匹配。 – gphilip 2011-05-11 14:35:27

+10

同意,再加上它會更容易,更有效的間諜方法調用如果在()指數將在每個方法的基礎上遞增。 – 2011-05-31 12:33:56

+1

看起來像任何錯誤的預期使用將導致「模擬方法不存在」的消息。很高興知道。 – 2012-10-02 00:17:21

1

據我可以告訴從演示代碼它應該工作。如果你正在運行一個較舊的PHPUnit版本,並且想要檢查它是否適用於你,我也製作了一個工作示例。

如果沒有幫助,也許你可以提供更多(最好的可執行文件)代碼? :)

<?php 

class MyTest extends PHPUnit_Framework_TestCase 
{ 

    public function testThis() 
    { 
     $mock = $this->getMock('MyClass'); 
     $mock->expects($this->at(0)) 
      ->method('exists') 
      ->with($this->equalTo('foo')) 
      ->will($this->returnValue(true)); 

     $mock->expects($this->at(1)) 
      ->method('exists') 
      ->with($this->equalTo('bar')) 
      ->will($this->returnValue(false)); 

     $this->assertTrue($mock->exists("foo")); 
     $this->assertFalse($mock->exists("bar")); 
    } 

} 

class MyClass { 

    public function exists($foo) { 
     return false; 
    } 
} 

打印

phpunit MyTest.php 
PHPUnit 3.4.15 by Sebastian Bergmann. 

. 

Time: 0 seconds, Memory: 4.25Mb 

OK (1 test, 3 assertions) 
0

你確定你包括在您的測試MyClass的?嘲諷類/接口而不包含它時,我有一些未定義的方法錯誤。

+0

是的,第一個匹配工作正常,這是摸不到頭腦 – 2010-07-30 17:03:56

16

僅供參考,不知道它的相關,但我遇到了同樣的事情,但不與$this->at()方法,對我來說這是$this->never()方法。

這引發的錯誤

$mock->expects($this->never()) 
    ->method('exists') 
    ->with('arg'); 

這種固定的錯誤

$mock->expects($this->never()) 
    ->method('exists'); 

它使用$this->exactly(0)方法時做同樣的事情。

希望這可以幫助別人。

+0

謝謝!這真的很有幫助,我遇到了同樣的問題,並且我被卡住了(直到我閱讀了你的評論)。 – 2013-09-25 09:48:52

+0

同樣的問題在這裏,非常感謝! – Mansiemans 2014-02-09 15:34:19

+0

謝謝,這也解決了我的問題。但我真的不知道它爲什麼起作用。你能否就這個問題提出一些看法? – 2014-02-20 09:12:57

4

嘗試改變$this->at(1)$this->at(2)

+0

爲我工作。在foo之後,我調用了一次''''foo''''和3次''''bar''''方法。從1個固定問題開始''''bar''''期望。 – 2014-12-02 14:04:17

2

這是通過PHPUnit的錯誤消息的一個不幸的措辭。

仔細檢查您的通話順序,如@ RR的回答中提到。

對我來說,只要我知道我自己的代碼,我應該是分別以at(0)at(1),但它不是,直到我用at(2)at(3)而不是它的工作。 (我使用的會議CakePHP的嘲笑。)

的最佳方式檢查訂單是讓「到」調用的方法,並檢查什麼過去了。你可以是這樣做的:

$cakePost = $this->getMock('CakePost'); 
$cakePost->expects($this->once()) 
->method('post') 
->with(
    // Add a line like this for each arg passed 
    $this->callback(function($arg) { 
     debug("Here's what was passed: $arg"); 
    }) 
);