Frage phpunit vermeidet Konstruktorargumente für Mock


Wie vermeidet man, dass phpunit den Konstruktor für ein Mock-Objekt aufrufen muss? Ansonsten würde ich ein Mock-Objekt als Konstruktorargument, ein anderes für das usw. brauchen. Die API scheint so zu sein:

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

Ich bekomme es nicht zur Arbeit. Es klagt immer noch über das Konstruktorargument, sogar mit $callOriginalConstructor auf falsch gesetzt.

Ich habe nur ein Objekt im Konstruktor und es ist eine Abhängigkeitsinjektion. Also ich glaube nicht, dass ich dort ein Designproblem habe.


76
2017-11-10 23:00


Ursprung


Antworten:


Sie können verwenden getMockBuilder statt nur getMock:

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

Siehe den Abschnitt über "Test Doppelgänger" im PHPUnit-Dokumentation für Details.

Obwohl Sie dies tun können, ist es viel besser, nicht zu müssen. Sie können Ihren Code so umgestalten, dass Sie anstelle einer konkreten Klasse (mit einem Konstruktor), die injiziert werden muss, nur auf eine Schnittstelle angewiesen sind. Dies bedeutet, dass Sie die Schnittstelle nachahmen oder stubben können, ohne PHPUnit mitteilen zu müssen, das Konstruktorverhalten zu ändern.


125
2018-06-08 10:11



Bitte schön:

    // 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);

40
2018-03-09 22:38



Als Anhang wollte ich anhängen expects() ruft mein verspottetes Objekt auf und ruft dann den Konstruktor auf. In PHPUnit 3.7.14 das Objekt, das beim Aufruf zurückgegeben wird disableOriginalConstructor() ist buchstäblich ein Objekt.

// 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)

Leider gibt es in PHP 5.4 eine neue Option, die sie nicht verwenden:

ReflectionClass :: newInstanceWithoutConstructor

Da dies nicht verfügbar war, musste ich die Klasse manuell reflektieren und dann den Konstruktor aufrufen.

$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);

Beachten Sie, wenn functionCallFromConstruct ist protected, müssen Sie speziell verwenden setMethods() damit die geschützte Methode verspottet wird. Beispiel:

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

setMethods() muss vor dem aufgerufen werden expect() Anruf. Persönlich kette ich das danach disableOriginalConstructor() Aber vorher getMock().


3
2018-03-08 02:21



Vielleicht müssen Sie einen Stub erstellen, der als Konstruktorargument übergeben wird. Dann können Sie diese Kette von Scheinobjekten aufbrechen.


1
2017-12-01 22:30



Alternativ könnten Sie einen Parameter hinzufügen getMock um den Aufruf des Standardkonstruktors zu verhindern.

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

Trotzdem finde ich die Antwort von dave1010 schöner, dies nur der Vollständigkeit halber.


1
2017-07-21 07:37



PHPUnit wurde entwickelt, um den Konstruktor für mockige Objekte aufzurufen. Um dies zu verhindern, solltest du entweder:

  1. Injizieren Sie ein Mock-Objekt als Abhängigkeit in das Objekt, bei dem Sie sich nicht mokieren können
  2. Erstellen Sie eine Testklasse, die die Klasse erweitert, die Sie aufrufen möchten und die den übergeordneten Konstruktor nicht aufruft

0
2017-12-08 21:08