2012-08-09 35 views
2

我正在構建一個會話管理類和相關的單元測試。爲了將類與$ _SESSION的全局狀態分開,我使用了一個非常簡單的類來管理類和會話數據之間的綁定。PHPUnit模擬,每次返回相同的數組

Binding類的整個源如下:

class Binding implements iface\Binding 
{ 
    public function &getNamespace ($namespace) 
    { 
     return $_SESSION [$namespace]; 
    } 
} 

在消耗Session類我有以下:

protected function initStorage() 
{ 
    // Check that storage hasn't already been bound to the session 
    if ($this -> storage === NULL) 
    { 
     // Attempt to start the session if it hasn't already been started 
     if (($this -> sessionId() !== '') 
     || ((!$this -> headersSent()) 
     && ($this -> startSession()))) 
     { 
      // Bind the storage to the session 
      $this -> storage =& $this -> binding -> getNamespace ($this -> namespace); 
      // Make sure the session is in a usable state 
      if (!$this -> hasData()) 
      { 
       $this -> reset(); 
      } 
     } 
     else 
     { 
      // We couldn't start the session 
      throw new \RuntimeException (__METHOD__ . ': Unable to initiate session storage at this time'); 
     } 
    } 

    return $this; 
} 

的sessionId,headersSent和startSession是簡單的一行功能作爲「測試接縫」,我可以很容易地用PHPUnit中的模擬代替它。

我意識到在編寫測試時,我可以使用模擬綁定類做更多的事情,而不僅僅是從類中分離會話,我還可以將它用作觀察類的非公共屬性的一種方式,而無需實際上暴露了任何內部狀態,從而使這個階級變得脆弱。由於該類對數組的引用進行操作,而不是直接對數組進行操作,因此我可以觀察被引用的數組。

我一直希望用PHPUnit的模擬API來做到這一點,但我不知道該怎麼做。

我知道我可以創建一個返回一個這樣的數組進行模擬:

$mock = $this -> getMock ('iface\Binding'); 

$mock -> expects ($this -> any()) 
     -> method ('getNamespace') 
     -> will ($this -> returnValue (array())); 

這不是因爲雖然觀察狀態的改變是有用的,因爲它返回每一次不同的陣列。我需要的是每次都返回一個對同一個數組的引用的模擬。

最後,我寫了一個類採取實際Binding類的地方,並使用來代替:

class BindingMock implements iface\Binding 
{ 
    protected $storage = array(); 

    public function &getNamespace ($namespace) 
    { 
     return $this -> storage [$namespace]; 
    } 
} 

使用這個類讓我前和調用的東西后,檢查$存儲的內容會話API,因爲我可以查看存儲陣列中的內容,而不必在Session類中公開非公共狀態。下面是一個使用該技術的試驗例:

public function testCreateItem() 
{ 
    $storage =& $this -> binding -> getNamespace ('unittest'); 
    $this -> assertEmpty ($storage); 
    $this -> object -> createItem ('This is a test', 'test'); 
    $this -> assertNotEmpty ($storage); 
    $this -> assertEquals ('This is a test', $storage ['test']); 
} 

我寧願能夠生成使用PHPUnit的,但替代類,具有附加類只是單元測試似乎是錯誤的方式做到這一點,除非在PHPUnit中無法實現同樣的功能。

+0

偏題...不錯的頭像! – Jrod 2012-08-09 22:18:15

回答

0

我認爲你可以返回一個ArrayObject公開內部數組到你的測試,但我寧願在這種情況下,以避免從Binding暴露數組。相反,接口應提供方法來獲取,設置和清除值以及其他更高級別的操作。然後你可以傳入一個模擬對象,它需要這些調用,而不是返回一個原始數組的那個對象。

相關問題