Frage

Für Objekte, die ein anderes Objekt als Teil ihrer Umsetzung zu komponieren, was ist der beste Weg, um das Gerät zu testen, so dass nur das Prinzip Objekt getestet wird zu schreiben? Triviales Beispiel:

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

Ich weiß, dass das Objekt entworfen werden könnte, so dass die Logger Objektabhängigkeit injiziert werden kann und somit in einem Unit-Test verspottet, aber das ist nicht immer der Fall ist - in komplizierteren Szenarien, müssen Sie auf andere Objekte komponieren oder Anrufe tätigen zu statischen Methoden.

Als wir das Logger-Objekt nicht testen wollen, nur die myObj, wie gehen wir vor? Haben wir eine gekürzte „double“ mit dem Testskript erstellen? So etwas wie:

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

class TestMyObj extends PHPUnit_Framework_TestCase 
{
    // ...
}

Dies scheint für kleine Objekte möglich aber wäre ein Schmerz für kompliziertere APIs sein, wo der SUT auf den Rückgabewerten abhängig. Auch was, wenn Sie die Anrufe auf das Abhängigkeitsobjekt im selben Test wurde Sie mit Mock-Objekte können? Gibt es eine Möglichkeit, Objekte von spöttischen, die eher von den SUT instanziiert werden als in weitergegeben werden?

Ich habe den Mann Seite auf Mocks lesen, aber es scheint nicht, diese Situation zu erfassen, in denen die Abhängigkeit besteht nicht aggregiert. Wie machen Sie das?

War es hilfreich?

Lösung

Wie Sie scheinen schon bewusst zu sein, konkrete Klasse Abhängigkeiten machen das Testen schwer (oder gar unmöglich). Sie müssen diese Abhängigkeit entkoppeln. Eine einfache Änderung, die nicht die vorhandene API nicht bricht, ist auf das aktuelle Verhalten auf Standard, sondern bietet einen Haken es außer Kraft zu setzen. Es gibt eine Reihe von Möglichkeiten, wie diese umgesetzt werden könnten.

Einige Sprachen haben Tools, die Mock-Klassen in Code injizieren, aber ich weiß nicht, wie dies für PHP von irgendetwas. In den meisten Fällen würden Sie wahrscheinlich besser dran Code sowieso Refactoring.

Andere Tipps

Im Anschluss an troelskn rät hier ist ein einfaches Beispiel von dem, was Sie tun sollen.

<?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
    }
}

Weitere Informationen über Mock-Objekte können im Handbuch .

Sieht aus wie ich die Frage falsch verstanden, lassen Sie mich noch einmal versuchen:

Sie sollten das Singletonmuster oder eine Fabrik für den Logger verwenden, wenn es nicht zu spät ist schon:

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

Wenn Sie den Code nicht ändern, könnten Sie eine Catch-all-Klasse verwenden, die __ call ()

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

Es ist eigentlich eine relativ neue Erweiterung für Überlastungen PHP-Klasse mit den gleichen Jungs veröffentlicht, die PHPUnit bauen. Damit können Sie den neuen Operator in Fällen außer Kraft setzen, wo Sie den Code nicht Refactoring können, leider ist es nicht so einfach auf Windows zu installieren.

Die URL ist http://github.com/johannes/php -Test-Helfer / Blob / Master /

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top