2011-07-25 23 views
6

這不像是一個試圖在PHPUnit浪費時間的時候拯救別人的問題。在依賴PHPUnit測試之間傳遞的對象會發生什麼?

我的問題是,我的模擬對象,當用於依賴測試時,沒有返回期望值。似乎PHPUnit不保留相關測試之間的同一對象,即使語法看起來像它一樣。

有誰知道爲什麼PHPUnit會這樣做?這是一個錯誤?在PHPUnit中這樣的事情使其非常令人沮喪地使用非常

<?php 
class PhpUnitTest 
extends PHPUnit_Framework_TestCase 
{ 
private $mock; 

public function setUp() 
{ 
    $this->mock = $this->getMock('stdClass', array('getFoo')); 

    $this->mock->expects($this->any()) 
     ->method('getFoo') 
     ->will($this->returnValue('foo')); 
} 

public function testMockReturnValueTwice() 
{ 
    $this->assertEquals('foo', $this->mock->getFoo()); 
    $this->assertEquals('foo', $this->mock->getFoo()); 

    return $this->mock; 
} 

/** 
* @depends testMockReturnValueTwice 
*/ 
public function testMockReturnValueInDependentTest($mock) 
{ 
    /* I would expect this next line to work, but it doesn't! */ 
    //$this->assertEquals('foo', $mock->getFoo()); 

    /* Instead, the $mock parameter is not the same object as 
    * generated by the previous test! */ 
    $this->assertNull($mock->getFoo()); 
} 

} 
+0

如遇到問題,請添加命令行如何調用phpunit。 - 你有沒有一個理由讓'$ mock'成爲私人成員? – hakre

+1

AFAIK phpunit在每次測試之前運行setUp()方法,以便重置$ this-> mock的值 –

+0

我以爲這會在您寫下它時起作用,我認爲'setUp()'不會被調用@dependant測試,所以我真的很驚訝,那也失敗了......這可能會讓我很厭煩,如果我有一個模擬傳遞給一個類,我傳遞@depends :) – edorian

回答

5

PHPUnit中的模擬對象附加到爲其創建的測試實例,而這個定義意味着單個測試方法。這是因爲PHPUnit允許您指定在測試期間必須滿足的模擬期望。要做到這一點,一旦方法成功終止,就會斷言這些期望。如果模擬生活在測試中,預期將無法工作。

問題是,它不支持存根對象:只包含爲響應方法和輸入而採取的固定操作的模仿。存根不會驗證他們的方法被稱爲完全模擬。也許PHPUnit可以受益於在setUpBeforeClass()中創建與測試實例無關的存根的功能。

您的其他選擇是使用外部模擬對象庫,如MockeryPhake

編輯:再次查看您的示例代碼後,我想知道爲什麼您會對此行爲感到驚訝。 Shaunak寫道,在每個測試方法執行之前,對新實例調用setUp()。因此,每個實例都會收到一個新的模擬stdClass。如果您只想要一種測試方法來獲得期望,請將其添加到測試方法本身中。您仍然可以在setUp()中使用任何應該對所有測試方法都通用的行爲創建模擬對象。

+0

換句話說:在每次測試之後,在測試運行中創建的所有模擬對象都被剝離了所有指定的期望值? – edorian

+0

@David:我很困惑的原因是語法使得它看起來像dependee的返回值傳遞給depender。如果PHPUnit從頭開始重建所有東西,爲什麼它首先提供了這種誤導性語法? –

+0

@edorian - 期望值得到驗證,但AFAIK沒有被剝離。這種情況發生在測試方法成功完成但在調用'tearDown()'之前。雖然你可以在'tearDown()'中添加更多的期望和調用這個模擬,但這不會很有用。 –

2

我不是一個PHP的傢伙,所以糾正我,如果我錯了,但所有的單元測試的目的是在下面的順序運行,

設置 - >測試功能 - >破壞。

所以在執行任何測試函數之前每次調用安裝和銷燬函數。這是爲了保持單元測試的目的而完成的。

如果你想有獨立的單元測試用例,那麼你必須對它們進行編碼,而不是依賴於全局變量來做到這一點(這違背了單元測試的目的!)。如果存在依賴於某個函數的測試用例'A',則從'A'調用該函數,然後聲明這些值。

+0

該銷燬方法被命名爲'tearDown()'。 –

+0

這是正確的!對不起,我一般說話。 – Shaunak