2012-08-09 7 views
2

Я строю класс управления сеансом и связанный с ним модульный тест. Чтобы отделить класс от глобального состояния $ _SESSION, я использую чрезвычайно простой класс для управления связью между классом и данными сеанса.PHPUnit Mock, который возвращает один и тот же массив каждый раз

Весь источник 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 простые функции однолинейные которые служат в качестве «тестовых швов», которые я могу легко заменить на mocks в PHPUnit.

Я понял, что при написании теста я мог бы сделать больше с классом связывания привязки, чем просто отсоединить сеанс от класса, я мог бы также использовать его как способ наблюдения за непубличным свойством класса, фактически выставляют любое внутреннее состояние и тем самым делают класс хрупким. Поскольку класс работает с ссылкой на массив, а не непосредственно на массив, я могу наблюдать привязанный массив.

Я надеялся сделать это с издевательским API PHPUnit, но я не могу понять, как это сделать.

Я знаю, что могу создать макет, который возвращает массив так:

$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]; 
    } 
} 

Используя этот класс позволяет мне исследовать содержимое $ хранения до и после вызова что-то в Session 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

ответ

0

Я думаю, что вы можете вернуть ArrayObject, который подвергает внутренний массив вашим испытаниям, но я предпочел бы в этом случае избегать выделения массива из Binding. Вместо этого интерфейс Binding должен предоставлять методы для получения, установки и очистки значений наряду с другими операциями более высокого уровня. Затем вы можете передать объект-макет, который ожидает эти вызовы, а не тот, который возвращает необработанный массив.

Смежные вопросы