2014-02-21 5 views
0

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

Внутри одной из форм он создает экземпляр второго класса, и я изо всех сил пытаюсь понять, как я могу издеваться над зависимым объектом. Форма гласит:

class Default_Form_Timesheet extends G10_Form { 

    public function init() { 
    parent::init(); 

    $this->addElement('hidden', 'idTimesheet', array('filters' => array ('StringTrim'), 'required' => false, 'label' => false)); 
    $this->addElement('checkbox', 'storyFilter', array('label' => 'Show my stories')); 


    $user = new Default_Model_User(); 
    $this->addElement('select', 'idUser', array('filters' => array('StringTrim'), 'class' => 'idUser', 'required' => true, 'label' => 'User')); 
    $this->idUser->addMultiOption("",""); 
    $this->idUser->addMultiOptions($user->fetchDeveloper()); 
    ... 
    ...... 

Моя проблема возникает, когда вызов на $ user-> fetchDeveloper(). Я подозреваю, что у него есть что-то недоумение с насмешливыми объектами и инъекцией зависимостей, но любая оценка будет оценена. My Fail unit test выглядит следующим образом:

require_once TEST_PATH . '/ControllerTestCase.php'; 

class TimesheetValidationTest extends ControllerTestCase { 

    public $Timesheet; 
    public $UserStub; 
    protected function setUp() 
    { 
    $this->Timesheet = new Default_Model_Timesheet(); 
    parent::setUp(); 
    } 

    /** 
    * @dataProvider timesheetProvider 
    */ 
    public function testTimesheetValid($timesheet) { 

    $UserStub = $this->getMock('Default_Model_User', array('fetchDeveloper')); 
    $UserStub->expects($this->any()) 
     ->method('fetchDeveloper') 
     ->will($this->returnValue(array(1 => 'Mickey Mouse'))); 

    $Timesheet = new Default_Model_Timesheet(); 
    $this->assertEquals(true, $Timesheet->isValid($timesheet)); 
    } 

Мой поставщик данных - это отдельный файл.

Он заканчивается в командной строке без вывода, и я немного в тупике. Любая помощь будет принята с благодарностью.

+0

Вы можете издеваться над 'init()', или вам нужно убедиться, что внешний класс будет найден – hek2mgl

+0

Спасибо за отзыв.Класс User найден, он вызван в «fetchDeveloper», который, по-видимому, вызывает проблему. –

ответ

1

Вы не можете высмеять класс Default_Model_User в своем тесте на форму. Поскольку ваш код создает экземпляр класса внутри, вы не можете заменить его макетом.

У вас есть несколько вариантов тестирования этого кода.

Вы смотрите, что fetchDeveloper делает и контролирует то, что он возвращает. Либо через макет объекта, который вы можете ввести где-нибудь (выглядит маловероятным), либо путем установки некоторых данных, чтобы вы знали, какими будут данные. Это сделает ваш тест немного хрупким, поскольку он может сломаться, когда данные, которые вы используете, изменяются.

Другой вариант - реорганизовать код, чтобы вы могли передать макет в вашу форму. Вы можете установить конструктор, который позволит вам установить класс Default_Model_User, а затем вы сможете издеваться над ним с вашим тестом, как написано.

Конструктор хотел бы так:

class Default_Form_Timesheet extends G10_Form { 
    protected $user; 

    public function __construct($options = null, Default_Model_User $user = null){ 
     if(is_null($user)) { 
      $user = new Default_Model_User(); 
     } 
     $this->user = $user; 
     parent::__construct($options); 
    } 

Zend Framework позволяет опции должны быть переданы формы конструктора, который я не уверен, если вы используете в вашем коде в любом месте, так что это не должно нарушать какие-либо из вашей текущей функциональности , Когда снова можно передать необязательный Default_Model_User, чтобы не нарушить текущую функциональность. Вы должны установить значения для $this->user перед вызовом parent::__construct, иначе Zend выдает ошибку.

Теперь ваша функция инициализации будет меняться от:

$user = new Default_Model_User(); 

в

$user = $this->user; 

В тесте теперь вы можете пройти в вашем макете объекта, и он будет использоваться.

public function testTimesheetValid($timesheet) { 

    $UserStub = $this->getMock('Default_Model_User', array('fetchDeveloper')); 
    $UserStub->expects($this->any()) 
     ->method('fetchDeveloper') 
     ->will($this->returnValue(array(1 => 'Mickey Mouse'))); 

    $Timesheet = new Default_Model_Timesheet(null, $UserStub); 
    $this->assertEquals(true, $Timesheet->isValid($timesheet)); 
} 

Создание издеваться не заменяет объект, так что, когда new называется, что ваш фиктивный объект создается. Он создает новый объект, который расширяет ваш класс, который вы теперь можете обойти. new - это смерть для проверки.

+0

Превосходный ответ, спасибо большое. Делает совершенный смысл. –

+0

Хотя я думаю, что имеет смысл изменить код, чтобы получить лучшую тестируемость, я думаю, что это неправильный ответ на тему «Как протестировать некоторый унаследованный код». Я бы искал способ проверить это, не меняя код. Я просто упоминаю об этом. :) – hek2mgl

+0

@ hek2mgl Я дал два варианта. Один из них позволяет не изменять код (использовать доступные данные и не пытаться имитировать вещи), другой - изменение кода. – Schleis

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