webentwicklung-frage-antwort-db.com.de

phpunit vermeidet Konstruktorargumente für Mock

Wie kann vermieden werden, dass phpunit den Konstruktor für ein Scheinobjekt aufrufen muss? Andernfalls würde ich ein Mock-Objekt als Konstruktor-Argument benötigen, ein anderes dafür usw. Die API scheint so zu sein:

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

Ich bringe es nicht zum Laufen. Es beschwert sich immer noch über das Konstruktorargument, auch mit $callOriginalConstructor auf false gesetzt.

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

80
Koen

Sie können getMockBuilder anstelle von getMock verwenden:

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

Weitere Informationen finden Sie im Abschnitt zu "Test Doubles" in Dokumentation von PHPUnit .

Obwohl Sie dies tun können, ist es viel besser, dies nicht zu müssen. Sie können Ihren Code umgestalten, sodass Sie anstatt einer konkreten Klasse (mit einem Konstruktor), die eingefügt werden muss, nur von einer Schnittstelle abhängig sind. Dies bedeutet, dass Sie die Schnittstelle verspotten oder stummschalten können, ohne PHPUnit anweisen zu müssen, das Konstruktorverhalten zu ändern.

136
dave1010

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);
42
Matthew Purdon

Als Ergänzung wollte ich expects() Aufrufe an mein verspottetes Objekt anhängen und dann den Konstruktor aufrufen. In PHPUnit 3.7.14 ist das Objekt, das beim Aufruf von disableOriginalConstructor() zurückgegeben wird, 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 widerspiegeln 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);

Hinweis: Wenn functionCallFromConstructprotected ist, müssen Sie setMethods() verwenden, damit die geschützte Methode verspottet wird. Beispiel:

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

setMethods() muss vor dem expect() -Aufruf aufgerufen werden. Persönlich verkette ich dies nach disableOriginalConstructor(), aber vor getMock().

3
Steve Tauber

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

1
Glenn Moss

Alternativ können Sie getMock einen Parameter hinzufügen, 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 ist nur der Vollständigkeit halber.

1
Hans Wouters

PHPUnit ruft den Konstruktor für verspottete Objekte auf. Um dies zu verhindern, sollten Sie entweder:

  1. Injizieren Sie ein Scheinobjekt als Abhängigkeit in das Objekt, für das Sie Probleme beim Verspotten haben
  2. Erstellen Sie eine Testklasse, die die aufzurufende Klasse erweitert, ohne den übergeordneten Konstruktor aufzurufen
0
silfreed