Undefined метод на mock-объекте, реализующем данный интерфейс в PHPUnit? - программирование
Подтвердить что ты не робот

Undefined метод на mock-объекте, реализующем данный интерфейс в PHPUnit?

Я новичок в модульном тестировании и PHPUnit.

Мне нужен макет, на котором у меня есть полный контроль, реализующий интерфейс ConfigurationInterface. Объектом тестирования является объект ReportEventParamConverter, и тест должен проверять взаимодействие между моим объектом и интерфейсом.

ReportEventParamConverter объект (здесь упрощенный):

class ReportEventParamConverter implements ParamConverterInterface
{
    /**
     * @param Request $request
     * @param ConfigurationInterface $configuration
     */
    function apply(Request $request, ConfigurationInterface $configuration)
    {
        $request->attributes->set($configuration->getName(), $reportEvent);
    }

    /**
     * @param ConfigurationInterface $configuration
     * @return bool
     */
    function supports(ConfigurationInterface $configuration)
    {
        return 'My\Namespaced\Class' === $configuration->getClass();
    }
}

И вот как я пытаюсь высмеять интерфейс:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls);

Мне нужно смоделировать возвращаемые значения для двух методов: getClass() и getName(). Например:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'))
;

Когда я создаю новый метод ReportEventParamConverter и test supports(), я получаю следующую ошибку PHPUnit:

Неустранимая ошибка: вызов метода undefinedMock_ConfigurationInterface_21e9dccf:: GetClass().

$converter = new ReportEventParamConverter();
$this->assertFalse($converter->supports($mock));
4b9b3361

Ответ 1

Это потому, что в ConfigurationInterface нет объявления метода getClass. Единственным объявлением в этом интерфейсе является метод getAliasName.

Все, что вам нужно, - это рассказать, какие методы вы будете заглушать:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls, array('getClass', 'getAliasName'));

Обратите внимание, что нет объявления "getClass", но вы также можете заглушить/измотать не существующий метод. Поэтому вы можете издеваться над этим:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'));

Но в добавлении вам нужно издеваться над методом getAliasName, а также до тех пор, пока это интерфейсный метод или абстрактный, и он должен быть "реализован". Например:.

$mock->expects($this->any())
   ->method('getAliasName')
   ->will($this->returnValue('SomeValue'));

Ответ 2

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

$mock = $this->getMock('SomeClassThatDoesntExistOrIsMisspelledOrPerhapsYouForgotToRequire');

Это означает, что если ConfigurationInterface не существует в этой точке во время выполнения, вы все равно получите сообщение типа

Неустранимая ошибка: вызов метода undefinedMock_ConfigurationInterface_21e9dccf:: GetClass().

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


OP использует интерфейс. Имейте в виду, что вы должны вызвать getMock, не указав список методов для переопределения, или если вы это сделаете, вы должны либо пройти array(), либо передать ВСЕ имена методов, либо вы получите сообщение об ошибке, как показано ниже:

PHP Неустранимая ошибка: класс Mock_HttpRequest_a7aa9ffd содержит 4 тега методов и поэтому должны быть объявлены абстрактными или реализовать остальные методы (HttpRequest:: setOption, HttpRequest:: execute, HttpRequest:: getInfo,...)

Ответ 3

Предупреждение Tyler Collier справедливо, но не содержит фрагмента кода о том, как его кодировать. Обратите внимание, что это очень неприятно, и вы должны исправить интерфейс. С этим предупреждением добавлено:

$methods = array_map(function (\ReflectionMethod $m) { return $m->getName();}, (new \ReflectionClass($interface))->getMethods());
$methods[] = $missing_method;
$mock = $this->getMock($interface,  $methods);