Phpunit избежать аргументов конструктора для mock

Каким образом можно избежать вызова phpunit для вызова конструктора для макета? В противном случае мне понадобился бы mock-объект в качестве аргумента конструктора, другой для этого и т.д. Api выглядит следующим образом:

getMock($className, $methods = array(), array $arguments = array(),
        $mockClassName = '', $callOriginalConstructor = TRUE,
        $callOriginalClone = TRUE, $callAutoload = TRUE)

Я не работаю. Он все еще жалуется на аргумент конструктора, даже если $callOriginalConstructor установлен в false.

У меня есть только один объект в конструкторе, и это инъекция зависимости. Поэтому я не думаю, что у меня есть проблема с дизайном.

Ответ 1

Вместо getMock вы можете использовать getMockBuilder:

$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

Подробнее см. в разделе "Двойные тесты" в документации PHPUnit.

Хотя вы можете это сделать, гораздо лучше не нужно. Вы можете реорганизовать свой код, поэтому вместо конкретного класса (с конструктором), который необходимо ввести, вы будете зависеть только от интерфейса. Это означает, что вы можете высмеять или заглушить интерфейс, не указав PHPUnit на изменение поведения конструктора.

Ответ 2

Здесь вы идете:

    // Get a Mock Soap Client object to work with.
    $classToMock = 'SoapClient';
    $methodsToMock = array('__getFunctions');
    $mockConstructorParams = array('fake wsdl url', array());
    $mockClassName = 'MyMockSoapClient';
    $callMockConstructor = false;
    $mockSoapClient = $this->getMock($classToMock,
                                     $methodsToMock,
                                     $mockConstructorParams,
                                     $mockClassName,
                                     $callMockConstructor);

Ответ 3

В качестве добавления я хотел прикрепить вызовы expects() к моему издеваемому объекту, а затем вызвать конструктор. В PHPUnit 3.7.14 объект, который возвращается при вызове disableOriginalConstructor(), буквально является объектом.

// Use a trick to create a new object of a class
// without invoking its constructor.
$object = unserialize(
sprintf('O:%d:"%s":0:{}', strlen($className), $className)

К сожалению, в PHP 5.4 есть новый параметр, который они не используют:

ReflectionClass:: newInstanceWithoutConstructor

Поскольку это не было доступно, мне пришлось вручную отобразить класс, а затем вызвать конструктор.

$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

$mock->expect($this->once())
    ->method('functionCallFromConstructor')
    ->with($this->equalTo('someValue'));

$reflectedClass = new ReflectionClass('class_name');
$constructor = $reflectedClass->getConstructor();
$constructor->invoke($mock);

Обратите внимание, что если functionCallFromConstruct - protected, вам нужно использовать setMethods(), чтобы защищенный метод издевался. Пример:

    $mock->setMethods(array('functionCallFromConstructor'));

setMethods() необходимо вызвать перед вызовом expect(). Лично я связываю это через disableOriginalConstructor(), но до getMock().

Ответ 4

Возможно, вам нужно создать заглушку для передачи в качестве аргумента конструктора. Затем вы можете разбить эту цепочку макетных объектов.

Ответ 5

В качестве альтернативы вы можете добавить параметр getMock, чтобы предотвратить вызов конструктора по умолчанию.

$mock = $this->getMock(class_name, methods = array(), args = array(), 
        mockClassName = '', callOriginalConstructor = FALSE);

Тем не менее, я думаю, что ответ dave1010 выглядит лучше, это только ради полноты.

Ответ 6

PHPUnit предназначен для вызова конструктора на издевающихся объектах; для предотвращения этого вам необходимо:

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