Методы PHPUnit Stubbing Class объявлены как "final" - PullRequest
15 голосов
/ 20 июня 2010

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

пример:

класс для насмешки

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'));
    }
}

Редактировать: Если вы используете решение, предоставленное Майком Б, и у вас есть установщик / получатель для объекта, который вы смоделируете, который выполняет проверку типа (чтобы убедиться, что правильный объект был передан в установщик), вам нужно будет смоделировать метод получения класса, который вы тестируете, и верните другой макет.

пример:

класс для насмешки

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();
    }
}

Ответы [ 2 ]

14 голосов
/ 20 июня 2010

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

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

Обнаружено в Руководстве по PHPUnit в разделе Глава 11. Test Doubles

Ограничения

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

5 голосов
/ 25 февраля 2014

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

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

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'));
        ...
    }
}
...