PHPUnit içinde bağımlılıkları ile nesneleri test

5 Cevap php

Bunların uygulanmasının bir parçası olarak başka bir nesne oluşturmak nesneler için, birim test yüzden sadece ilke nesne test alır yazmak için en iyi yolu nedir? Önemsiz bir örnek:

class myObj { 
    public function doSomethingWhichIsLogged()
    {
        // ...
        $logger = new logger('/tmp/log.txt');
        $logger->info('some message');
        // ...
    }
}

Ben logger nesne bağımlılık enjekte ve dolayısıyla bir birim test alay böylece nesne tasarlanmış olabileceğini biliyorum, ama bu her zaman böyle değil - daha karmaşık senaryolarda, diğer nesneleri oluşturmak veya statik yöntemleri aramaları yapmak gerekiyor .

Biz logger nesneyi, sadece myObj test etmek istemiyoruz, biz nasıl devam edeceğiz? Biz test script ile söndürdü "çift" oluşturmak mı? Gibi bir şey:

class logger
{
    public function __construct($filepath) {}
    public function info($message) {}
}

class TestMyObj extends PHPUnit_Framework_TestCase 
{
    // ...
}

Bu küçük nesneler için uygun görünüyor ama SUT dönüş değerlerine bağlıydı daha karmaşık API'ler için bir ağrı olur. Ayrıca, size davalarını nesneleri ile can aynı bağımlılık nesnesi çağrıları test etmek ne oldu isterseniz? Içinde geçirilen yerine SUT tarafından örneği nesneleri alaycı bir yolu var mı?

Ben mocks üzerinde man sayfasını okudum ama bağımlılık oluşan ziyade toplandığında bu durumu karşılamak için görünmüyor. Bunu nasıl yapabilirim?

5 Cevap

Zaten farkında olmak gibi görünüyor, Beton Sınıfı bağımlılıklar test sert (ya da düpedüz imkansız) yapar. Bunu bağımlılık decouple gerekir. Varolan API kırmak değil basit bir değişiklik, mevcut davranış varsayılan, ama bunu geçersiz kılmak için bir kanca sağlamaktır. Bu uygulanabilir bir kaç yolu vardır.

Bazı diller koduna sahte sınıfları enjekte araçları vardır, ama PHP için böyle bir şey bilmiyorum. Çoğu durumda, muhtemelen zaten senin kod üstlenmeden daha iyi olurdu.

Yapmanız gereken çok temel bir örnek troelskn burada tavsiye ediyor ardından.

<?php

class MyObj
{
    /**
     * @var LoggerInterface
     */
    protected $_logger;

    public function doSomethingWhichIsLogged()
    {
        // ...
        $this->getLogger()->info('some message');
        // ...
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->_logger = $logger;
    }

    public function getLogger()
    {
        return $this->_logger;
    }
}


class MyObjText extends PHPUnit_Framework_TestCase
{
    /**
     * @var MyObj
     */
    protected $_myObj;

    public function setUp()
    {
        $this->_myObj = new MyObj;
    }

    public function testDoSomethingWhichIsLogged()
    {
        $mockedMethods = array('info');
        $mock = $this->getMock('LoggerInterface', $mockedMethods);
        $mock->expects($this->any())
             ->method('info')
             ->will($this->returnValue(null));

        $this->_myObj->setLogger($mock);

        // do your testing
    }
}

Mock nesneler hakkında daha fazla bilgi bulunabilir in the manual.

Sen test doc-yorum içinde bağımlılık bilgi verebilir:

/**
 * @depends otherTestClass::testSomethingElse
 */
public function testSomething() { ...

You can find more information following this link

Ben soruyu yanlış gibi görünüyor, beni tekrar deneyelim:

Siz zaten çok geç değilse, singleton deseni veya logger için bir fabrika kullanmak gerekir:

class LoggerStub extends Logger {
    public function info() {}
}
Logger::setInstance(new LoggerStub());
...
$logger = Logger::getInstance();

Eğer kodunu değiştirmek yapamıyorsanız, aşırı yükleme bir catch-all sınıfını kullanabilirsiniz __call()

class GenericStub {
    public function __call($functionName, $arguments) {}
}

Phpunit inşa aynı adamlar tarafından yayımlanan PHP sınıfı aşırı yüklenmelerden için oldukça yeni bir uzantısı aslında yoktur. Bu size kod refactor olamaz durumlarda yeni operatörü, ne yazık ki Windows yüklemek için bu kadar basit değil geçersiz sağlar.

URL http://github.com/johannes/php-test-helpers/blob/master/