2012-02-26 54 views
0

我正在研究一組組件(希望能成爲一個完整的框架),並且目前正致力於提供一個PHP會話的抽象。構建一個更可測試的會話管理器

我試圖讓代碼儘可能地成爲可測試的,但是按照定義,會話類將以$ _SESSION超全局的形式依賴於全局狀態。

我試圖實現這樣的方式$ SESSION和會話 *函數只被調用在一個地方,我就可以在PHPUnit的覆蓋用於測試目的我的會話課,但我不能幫但不知道是否有更好的方法來做到這一點。

如果你可以建議一個更好的方法來做一個可測試的會話類,那麼我會很感激你可能有任何輸入。

/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 

namespace gordian\reefknot\storage\session; 

use gordian\reefknot\storage; 

/** 
* Session management 
* 
* Each instance of the Session object represents a "namespace" within the PHP 
* $_SESSION system. This allows sessions to be easily managed and organized 
* within an application 
* 
*/ 
class Session implements storage\iface\Crud, iface\Session 
{ 

    protected 
     $name  = '', 
     $storage = NULL; 


    /** 
    * Add a new item to the session 
    * 
    * @param mixed $data 
    * @param string $key 
    * @return Session 
    * @throws \InvalidArgumentException Thrown if no name is provided 
    */ 
    public function createItem ($data, $key) 
    { 
     if (!empty ($key)) 
     { 
      $key = (string) $key; 
      if (($this -> storage === NULL) 
      || (!array_key_exists ($key, $this -> storage))) 
      { 
       $this -> storage [$key] = $data; 
      } 
     } 
     else 
     { 
      throw new \Exception ('No valid key given'); 
     } 
     return ($this); 
    } 

    /** 
    * Delete the specified key 
    * 
    * @param string $key 
    * @return Session 
    */ 
    public function deleteItem ($key) 
    { 
     unset ($this -> storage [$key]); 
     return ($this); 
    } 

    /** 
    * Retrieve the data stored in the specified key 
    * 
    * @param type $key 
    * @return mixed 
    */ 
    public function readItem ($key) 
    { 
     return (array_key_exists ($key, $this -> storage)? 
      $this -> storage ['key']: 
      NULL); 
    } 

    /** 
    * Update a previously stored data item to a new value 
    * 
    * @param mixed $data 
    * @param string $key 
    */ 
    public function updateItem ($data, $key) 
    { 
     if ($this -> storage === NULL) 
     { 
      throw new \RuntimeException ('Session contains no data'); 
     } 

     if (array_key_exists ($key, $this -> storage)) 
     { 
      $this -> storage [$key] = $data; 
     } 
     return ($this); 
    } 

    /** 
    * Clear the session of all stored data 
    * 
    * @return Session 
    */ 
    public function reset() 
    { 
     $this -> storage = NULL; 
     return ($this); 
    } 

    /** 
    * Retrieve all data stored in the session 
    * 
    * @return array 
    */ 
    public function getAll() 
    { 
     return ($this -> storage); 
    } 

    /** 
    * Return whether there is data stored in this session 
    * 
    * @return bool 
    */ 
    public function hasData() 
    { 
     return (!empty ($this -> storage)); 
    } 

    /** 
    * Initialize the back-end storage for the session 
    * 
    * This method provides access for this class to the underlying PHP session 
    * mechanism. 
    * 
    * @return bool Whether the newly initialized session contains data or not 
    * @throws \RuntimeException Will be thrown if the session failed to start 
    */ 
    protected function initStorage() 
    { 
     // Check that storage hasn't already been initialized 
     if ($this -> storage === NULL) 
     { 
      // Attempt to start the session if it hasn't already been started 
      if ((session_id() === '') 
      && ((headers_sent()) 
      || ((!session_start())))) 
      { 
       throw new \RuntimeException ('Unable to start session at this time'); 
      } 
      // Alias our instance storage to the named $_SESSION variable 
      $this -> storage =& $_SESSION [$this -> name]; 
     } 
     return ($this -> hasData()); 
    } 

    /** 
    * Class constructor 
    * 
    * @param string $sessName 
    * @throws \InvalidArgumentException Thrown if no session name is provided 
    */ 
    public function __construct ($sessName) 
    { 
     if (!empty ($sessName)) 
     { 
      $this -> name = $sessName; 
      $this -> initStorage(); 
     } 
     else 
     { 
      throw new \InvalidArgumentException ('Session must have a name'); 
     } 
    } 
} 

爲了測試,目前的計劃是與剛剛設置了一個內部數組代替的方法,以取代initStorage()。如果你能提出更好的方法,我會很樂意聽到它。

回答

1

如果我正確..已瞭解

創建本地會話管理的抽象,使您的會話存儲幫手並不需要真正做任何的session_的*電話或訪問$ _SESSION直接。

有兩個它的實現,一個實際上做的是正確的事情,而不是假的會話_ *()和$ _SESSION,並且在你的構造函數中你只需調用SESSIONCLASS :: start()和SESSIONCLASS :: getVar(name )。那麼你可以完全測試「Session」。

1

由於$_SESSION是一個常規數組,因此沒有理由通過引用來訪問它。各種讀/寫方法應該直接對其進行操作。您可以清除測試案例的setUp()方法中的陣列。使用該參考過分複雜化班級而沒有收益。

單元測試時,您不應該考慮測試內置的PHP函數,如session_id()headers_sent()。創建一個覆蓋此方法的類或僅測試子類的部分模擬。