2012-11-01 87 views
3

我有一些問題的理解模仿對象。PHPUnit的模擬只觀察

我想要的是一個觀察者,正常工作但確保使用正確的參數調用方法。

從我瞭解到目前爲止,這應該是什麼我在尋找: 觀察報:

class Observer 
{ 
    public function returnFooIfBar($bar) 
    { 
     return ($bar == 'bar') ? 'foo' : ; 
    } 
} 

主題:

class Subject 
{ 
    $obs; 
    __construct(Observer $dependency) 
    { 
     $this->obs = $dependency; 
    } 

    public function tradeStrings($string) 
    { 
     $this->obs->returnFooIfBar($string); 
    } 
} 

測試:

class SubjectTest 
{ 
    public function testCallsObsMethod() 
    { 
     $obs = $this->getMock('Observer') ; 
     $obs->expect($this->once()) 
      ->method('returnFooIfBar') 
      ->with($this->equlTo('bar')) ; 

     $subj = new Subject($obs); 
     $returnString= $subj->TradeStrings('bar') ; 

     $this->assertEqual('foo', $returnString) ; 
    } 
} 

從什麼我明白這個測試:

  1. 觀察員:: getFooIfBar被調用一次。
  2. 觀察員:: getFooIfBar得到字符串「酒吧」作爲類中定義,並返回「富」作爲一個字符串 3.方法的工作。

據我所知,沒有改變原始類的功能,除了構造函數/自動加載未被運行。

如果我在運行getMock()時嘲笑方法,模擬對象的方法將只有如果我指定它會返回一些東西。

$obs = $this->getMock('Observer', array('returnFooIfBar')); 
$obs->expects($this->once()) 
    ->method('returnFooIfBar') 
    ->with('bar') 
    ->will($this->returnValue('foo'); 

我理解這個權利嗎?如果不是的話,請你澄清一下,因爲我希望對此有所澄清。 :)

編輯:更改了帖子,使其更清晰我以後以及我目前如何理解它。

回答

7

如果讓PHPUnit的創建嘲笑的對象,它在內部建立了它擴展了原來的一個,並實現與模擬特定代碼此類的所有方法,新的臨時類。

這背後的想法是去耦在測試用例對象。而你給出的例子是有效的,你不會以這種方式使用它。 但您的示例測試無論如何都會失敗,因爲嘲笑功能returnStringFooIfBar不會返回任何東西。

這是應該如何工作的:

$obs = $this->getMock('observer') ; 
$obs->expect($this->once()) 
    ->method('returnStringFooIfBar') 
    ->with($this->equlTo('bar')) 
    ->will($this->returnValue('foo')); 

$returnString= $obs->returnStringFooIfBar ('bar') ; 
$this->assertEqual('foo', $returnString) ; 

而是一個真實的世界測試用例會涉及一些對象來測試:

class TestObject { 

    private $observer; 
    public function __construct($observer) { 
     $this->observer = $observer; 
    } 

    public function doMagicAndNotify() { 
     // do heavy magic 

     //notify observer 
     $obsresult = $this->observer->returnStringFooIfBar('bar'); 

     return 'didmagic'; 
    } 
} 

class TestObjectTest extends PHPUnit_Framework_TestCase { 

    public function testObserverCalling() { 
     $obs = $this->getMock('observer') ; 
     $obs->expect($this->once()) 
      ->method('returnStringFooIfBar') 
      ->with($this->equlTo('bar')); 

     $test = new TestObject($obs); 
     $returnString= $test->doMagicAndNotify() ; 

     $this->assertEqual('didmagic', $returnString) ; 
    } 
} 

編輯:

我希望是一個正常工作的觀察者,但確保使用正確的參數調用方法。

據我所知,沒有改變原始類的功能, 以外的構造函數/自動加載未運行。

實際上是相反的。 Observer的臨時子類會覆蓋所有(或指定的)方法並更改原始功能(簡單地不執行模擬方法的父代)。它不會覆蓋構造函數,無論如何它都會被調用。

不可能斷言模擬方法的方法調用並在相同的時間調用其原始方法。

請參閱Method Templatethe Generator以供參考。

而且請記住:你沒有在這裏測試你的觀察者的正確行爲,你正在嘲笑它的beheviour爲了測試主題。

sitenote:$this->returnCallback($someCallback)是一個強大的功能,可能會幫助你。 我不喜歡這個主意,但你可以做這樣的事情:

public function testObserverCalling() { 
    $obs = new Observer(); 
    $obsmock = $this->getMock('observer') ; 
    $obsmock->expect($this->once()) 
     ->method('returnStringFooIfBar') 
     ->with($this->equlTo('bar')) 
     ->will($this->returnCallback(array($obs, 'returnStringFooIfBar'))); 

    $test = new TestObject($obsmock); 
    $returnString= $test->doMagicAndNotify() ; 

    $this->assertEqual('didmagic', $returnString) ; 
} 
+1

+1 - 我有幾乎一模一樣的帖子一字排開,但你打我吧:-) – cmbuckley

+0

我已經改變我的帖子,試圖澄清我的看法,以及我如何理解這一刻的事情。 – Penetal

+0

我也進行了更改,請參閱我的編輯。 –