Pytanie phpunit unika argumentów konstruktora dla makiety


W jaki sposób uniknąć sytuacji, w której phpunit będzie musiał wywołać konstruktor w celu uzyskania fałszywego obiektu? W przeciwnym razie potrzebowałbym fałszywego obiektu jako argumentu konstruktora, innego dla tego itd. Wygląda na to, że api wygląda następująco:

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

Nie rozumiem, jak to działa. Nadal narzeka na argument konstruktora, nawet z $callOriginalConstructor ustaw na false.

Mam tylko jeden obiekt w konstruktorze i jest to zastrzyk zależności. Więc nie sądzę, że mam tam problem z projektowaniem.


76
2017-11-10 23:00


pochodzenie




Odpowiedzi:


Możesz użyć getMockBuilder zamiast po prostu getMock:

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

Zobacz rozdział na "Podwójne testy" w Dokumentacja PHPUnit dla szczegółów.

Chociaż możesz to zrobić, o wiele lepiej nie musisz. Możesz zreorganizować swój kod, aby zamiast konkretnej klasy (z konstruktorem) wymagającej iniekcji, zależy tylko od interfejsu. Oznacza to, że możesz symulować lub blokować interfejs bez konieczności powiadamiania PHPUnit o modyfikacji zachowania konstruktora.


125
2018-06-08 10:11



Działa to doskonale dla mnie. Jednak powinien to być przykład 10.3. Próbowałem edytować wpis, ale SO wyrzucił go, ponieważ był zbyt krótki. - Matthew
Dzięki @Lytithwyn. Zaktualizowano odpowiedź. - dave1010
działa również dla mnie. Dzięki! - Jeune


Proszę bardzo:

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



Wydaje się, że prawie to, czego chcę. Chcę wywołać getMock z kpiną z klasy i $ callMockConstructor. W jaki sposób? coś takiego: $ this-> getMock ($ classToMock, $ callMockConstructor). Jedyne co mogłem wymyślić to wejść w źródło PHPUnit i zmienić go na default = false. - Gutzofter
Zmieniłem domyślną wartość na false w pliku testcase.php. Można by pomyśleć, że domyślnie ustawiono na false. Kpiny z konstruktora wydają się bardzo dziwne - Gutzofter
OBTW, dziękuję! - Gutzofter
Doskonała odpowiedź. Właśnie tego szukałem - Hades


Jako dodatek, chciałem dołączyć expects() dzwoni do mojego wyśmianego obiektu, a następnie dzwoni do konstruktora. W PHPUnit 3.7.14, obiekt, który jest zwracany po wywołaniu disableOriginalConstructor() jest dosłownie obiektem.

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

Niestety w PHP 5.4 jest nowa opcja, której nie używają:

ReflectionClass :: newInstanceWithoutConstructor

Ponieważ nie było to możliwe, musiałem ręcznie odzwierciedlić klasę, a następnie wywołać konstruktora.

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

Uwaga, jeśli functionCallFromConstruct jest protected, konkretnie musisz użyć setMethods() aby kpiarka została zabezpieczona metodą chronioną. Przykład:

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

setMethods() musi być wywołany przed expect() połączenie. Osobiście łączę to po disableOriginalConstructor() ale przedtem getMock().


3
2018-03-08 02:21





Być może trzeba utworzyć kod pośredniczący, aby przekazać jako argument konstruktora. Wtedy możesz zerwać ten łańcuch fałszywych obiektów.


1
2017-12-01 22:30



czy mógłbyś podzielić się z nami kilkoma dodatkowymi informacjami - Deep Singh Baweja


Alternatywnie możesz dodać parametr do getMock aby zapobiec wywołaniu domyślnego konstruktora.

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

Nadal myślę, że odpowiedź dave1010 wygląda ładniej, to tylko ze względu na kompletność.


1
2017-07-21 07:37





PHPUnit jest przeznaczony do wywoływania konstruktora na wyśmianych obiektach; Aby temu zapobiec, należy:

  1. Wstaw obiekt pozorny jako zależność do obiektu, z którym masz problemy z kpiny
  2. Utwórz klasę testową, która rozszerza klasę, którą próbujesz wywołać, która nie wywołuje konstruktora nadrzędnego

0
2017-12-08 21:08