2010-06-20 3 views
14

Я пишу модульный тест для метода класса, который вызывает метод другого класса, используя макет, только метод, который нужно вызывать, объявляется окончательным, поэтому PHPUnit не может издеваться над ним. Есть ли другой подход, который я могу предпринять?PHPUnit Stubbing Методы класса, объявленные как «final»

пример:

класс поругаем

class Class_To_Mock 
{ 
    final public function needsToBeCalled($options) 
    { 
     ... 
    } 
} 

мой тест

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testDoSomething() 
    { 
     $mock = $this->getMock('Class_To_Mock', array('needsToBeCalled')); 
     $mock->expects($this->once()) 
      ->method('needsToBeCalled') 
      ->with($this->equalTo(array('option')); 
    } 
} 

Edit: При использовании решение, предложенное Майком B и у вас есть сеттер/getter для объекта, который вы издеваетесь, который проверяет тип (чтобы гарантировать, что правильный объект был передан в сеттер), yo Вам нужно высмеять геттер в классе, который вы тестируете, и попросите его вернуть другой макет.

пример:

класс поругаем

class Class_To_Mock 
{ 
    final public function needsToBeCalled($options) 
    { 
     ... 
    } 
} 

макет

class Class_To_MockMock 
{ 
    public function needsToBeCalled($options) 
    { 
     ... 
    } 
} 

класс для тестирования

class Class_To_Be_Tested 
{ 
    public function setClassToMock(Class_To_Mock $classToMock) 
    { 
     ... 
    } 

    public function getClassToMock() 
    { 
     ... 
    } 

    public function doSomething() 
    { 
     $this->getClassToMock() 
      ->needsToBeCalled(array('option')); 
    } 
} 

мой тест

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testDoSomething() 
    { 
     $classToTest = $this->getMock('Class_To_Be_Tested', array('getClassToMock')); 

     $mock = $this->getMock('Class_To_MockMock', array('needsToBeCalled')); 

     $classToTest->expects($this->any()) 
        ->method('getClassToMock') 
        ->will($this->returnValue($mock)); 

     $mock->expects($this->once()) 
      ->method('needsToBeCalled') 
      ->with($this->equalTo(array('option')); 

     $classToTest->doSomething(); 
    } 
} 

ответ

14

Я не думаю, что PHPUnit поддерживает stubbing/mocking окончательных методов. Вы, возможно, придется создать свой собственный заглушки для этой ситуации и сделать некоторые расширения фокусы:

class myTestClassMock { 
    public function needsToBeCalled() { 
    $foo = new Class_To_Mock(); 
    $result = $foo->needsToBeCalled(); 
    return array('option'); 
    } 
} 

Нашли это в Руководстве PHPUnit под Chapter 11. Test Doubles

Ограничения

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

+1

Ах, пропустил, что в руководстве, спасибо –

+0

Там это дополнительный шаг, вам нужно, если класс вы 're testing полагается на getter/setter, который выполняет проверку типа для класса/метода, издевающегося над ним. Я добавил это к исходному сообщению. –

+0

@rr Пожалуйста, подумайте над тем, чтобы добавить это как ответ, вместо того, чтобы помещать решение в вопрос. – BartoszKP

4

Я только что наткнулся на этот вопрос сегодня. Другой альтернативой является издевательство над интерфейсом, который реализует класс, учитывая, что он реализует интерфейс, и вы используете интерфейс как тип намекания.

Например, если проблема в вопросе, вы можете создать интерфейс и использовать его следующим образом:

interface Interface_To_Mock 
{ 
    function needsToBeCalled($options); 
} 

class Class_To_Mock implements Interface_To_Mock 
{ 
    final public function needsToBeCalled($options) 
    { 
     ... 
    } 

} 

class Class_To_Be_Tested 
{ 
    public function setClassToMock(Interface_To_Mock $classToMock) 
    { 
     ... 
    } 

    ... 
} 

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testDoSomething() 
    { 
     $mock = $this->getMock('Interface_To_Mock', array('needsToBeCalled')); 
     ... 
    } 
} 
Смежные вопросы