phpunit, sahte için yapıcı argümanlarından kaçınır


85

Phpunit'in kurucuyu sahte bir nesne için çağırmasını önlemenin yolu nedir? Aksi takdirde yapıcı argüman olarak sahte bir nesneye ihtiyacım olur, bunun için başka bir nesneye vb.

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

İşe yaramıyorum. Yine de yapıcı argümanından şikayet eder, $callOriginalConstructorfalse olarak ayarlanmış olsa bile .

Yapıcıda yalnızca bir nesnem var ve bu bir bağımlılık enjeksiyonu. Bu yüzden orada bir tasarım sorunum olduğunu sanmıyorum.

Yanıtlar:


139

Yalnızca aşağıdakiler getMockBuilderyerine kullanabilirsiniz getMock:

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

Bölümüne bakın "Test Çiftler" de PHPUnit belgelerine detayları için.

Bunu yapabilmenize rağmen, buna ihtiyaç duymamak çok daha iyidir. Kodunuzu yeniden düzenleyebilirsiniz, böylece somut bir sınıfın (bir kurucu ile) enjekte edilmesi yerine, yalnızca bir arayüze bağlı olursunuz. Bu, PHPUnit'e yapıcı davranışını değiştirmesini söylemenize gerek kalmadan arabirimle alay edebileceğiniz veya saplayabileceğiniz anlamına gelir.


Bu benim için harika çalışıyor. Yine de örnek 10.3 olmalıdır. Gönderiyi düzenlemeyi denedim ama çok kısa bir düzenleme olduğu için SO onu geri attı.
Matthew

Teşekkürler @Lytithwyn. Cevap güncellendi.
dave1010

42

Hadi bakalım:

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

Bu neredeyse istediğim gibi görünüyor. GetMock'u sadece alay edilecek sınıf ve $ callMockConstructor ile çağırmak istiyorum. Nasıl? bunun gibi bir şey: $ this-> getMock ($ classToMock, $ callMockConstructor). Aklıma gelen tek şey, PHPUnit'in kaynağına gitmek ve onu default = false olarak değiştirmektir.
Gutzofter

1
Testcase.php'de varsayılanı false olarak değiştirdim. Varsayılan olarak yanlış olarak ayarlanacağını düşünürsünüz. Bir
kurucuyla alay etmek

Mükemmel cevap. Tam aradığım şey
Hades

4

Ek olarak, expects()alay edilen nesneme çağrı eklemek ve ardından kurucuyu çağırmak istedim . PHPUnit 3.7.14'te, çağırdığınızda döndürülen disableOriginalConstructor()nesne tam anlamıyla bir nesnedir.

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

Ne yazık ki, PHP 5.4'te kullanmadıkları yeni bir seçenek var:

ReflectionClass :: newInstanceWithoutConstructor

Bu mevcut olmadığından, sınıfı manuel olarak yansıtmalı ve sonra kurucuyu çağırmalıydım.

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

Eğer Not functionCallFromConstructolduğunu protected, özel olarak kullanmak zorunda setMethods()korumalı yöntem alay böylece. Misal:

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

setMethods()expect()aramadan önce aranmalıdır. Şahsen bunu sonradan disableOriginalConstructor()ama önce zincirledim getMock().


Bunun bir kod kokusu olup olmadığı hakkında hiçbir fikrim yok, ama bu benim için harika çalıştı ve sadece teşekkür etmek istedim.
devbanana

1

Yapıcı argümanı olarak geçmek için bir saplama oluşturmanız gerekebilir. Sonra bu sahte nesneler zincirini kırabilirsiniz.


1

Alternatif olarak, varsayılan kurucunun çağrılmasını önlemek için getMock'a bir parametre ekleyebilirsiniz .

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

Yine de, dave1010'un cevabının daha güzel göründüğünü düşünüyorum, bu sadece eksiksizlik adına.


1

Bu soru biraz eskidir, ancak yeni ziyaretçiler için bunu createMockyöntemi kullanarak yapabilirsiniz (daha önce createTestDoublev5.4.0'da çağrılmış ve tanıtılmıştır).

$mock = $this->createMock($className);

Aşağıdaki kodda görebileceğiniz gibi, PHPUnit\Framework\TestCasesınıftan (in phpunit/src/framework/TestCase.php) çıkarılmış, temelde orijinal kurucuyu çağırmadan sahte bir nesne oluşturacaktır .

/** PHPUnit\Framework\TestCase::createMock method */
protected function createMock(string $originalClassName): MockObject
{
    return $this->getMockBuilder($originalClassName)
                ->disableOriginalConstructor()
                ->disableOriginalClone()
                ->disableArgumentCloning()
                ->disallowMockingUnknownTypes()
                ->getMock();
}

0

PHPUnit, alay edilen nesnelerde yapıcıyı çağırmak için tasarlanmıştır; Bunu önlemek için şunlardan birini yapmalısınız:

  1. Alay etmekte zorlandığınız nesneye bağımlılık olarak sahte bir nesne enjekte edin
  2. Ana kurucuyu çağırmayan, aramaya çalıştığınız sınıfı genişleten bir test sınıfı oluşturun
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.