11 Stimmen

Wie kann man einen Webdienst in PHPUnit über mehrere Tests hinweg als Mocktest verwenden?

Ich versuche, eine Web-Service-Schnittstelle-Klasse mit PHPUnit zu testen. Grundsätzlich macht diese Klasse Aufrufe an eine SoapClient Gegenstand. Ich versuche, diese Klasse in PHPUnit zu testen, indem ich die getMockFromWsdl hier beschriebenen Methode:

http://www.phpunit.de/manual/current/en/test-doubles.html#test-doubles.stubbing-and-mocking-web-services

Da ich jedoch mehrere Methoden derselben Klasse testen möchte, muss ich jedes Mal, wenn ich das Objekt einrichte, auch die Mock-WSDL einrichten SoapClient Objekt. Dies führt zu einem schwerwiegenden Fehler, der ausgelöst wird:

Fatal error: Cannot redeclare class xxxx in C:\web\php5\PEAR\PHPUnit\Framework\TestCase.php(1227) : eval()'d code on line 15

Wie kann ich ein und dasselbe Mock-Objekt in mehreren Tests verwenden, ohne es jedes Mal aus der WSDL neu generieren zu müssen? Das scheint das Problem zu sein.

--

Nachdem ich gebeten wurde, etwas Code zu posten, den ich mir ansehen kann, hier die Setup-Methode in der TestCase:

protected function setUp() {
    parent::setUp();

    $this->client = new Client();

    $this->SoapClient = $this->getMockFromWsdl(
        'service.wsdl'
    );

    $this->client->setClient($this->SoapClient);
}

4voto

James Dunmore Punkte 1190

Dies ist keine ideale Lösung, aber in Ihrem Setup geben Sie dem SOAP-Mock einen "zufälligen" Klassennamen, zum Beispiel

$this->_soapClient = $this->getMockFromWsdl( 'some.wsdl', 'SoapClient' . md5( time().rand() ) );

Dadurch wird sichergestellt, dass zumindest beim Aufruf des Setups keine Fehlermeldung angezeigt wird.

1voto

pestilence669 Punkte 5568

Für den einfachen Gebrauch würde so etwas funktionieren. PHPUnit vollbringt einige Zaubereien hinter den Kulissen. Wenn Sie das Mock-Objekt zwischenspeichern, wird es nicht neu deklariert. Erstellen Sie einfach eine neue Kopie von dieser zwischengespeicherten Instanz und Sie sollten gut zu gehen.

<?php
protected function setUp() {
    parent::setUp();

    static $soapStub = null; // cache the mock object here (or anywhere else)
    if ($soapStub === null)
        $soapStub = $this->getMockFromWsdl('service.wsdl');

    $this->client = new Client;
    $this->client->setClient(clone $soapStub); // clone creates a new copy
}
?>

Alternativ können Sie den Namen der Klasse wahrscheinlich auch mit get_class und erstellen Sie dann eine neue Instanz, anstatt eine Kopie. Ich bin nicht sicher, wie viel "Magie" PHPUnit für die Initialisierung tut, aber es ist einen Versuch wert.

<?php
protected function setUp() {
    parent::setUp();

    static $soapStubClass = null; // cache the mock object class' name
    if ($soapStubClass === null)
        $soapStubClass = get_class($this->getMockFromWsdl('service.wsdl'));

    $this->client = new Client;
    $this->client->setClient(new $soapStubClass);
}
?>

1voto

eyescream Punkte 14940

Warum erstellen Sie die Mock in setUp(), wenn der Punkt ist, um Mock-Klassendefinition einmal pro Ausführung der gesamten Testdatei zu erhalten? Wenn ich mich richtig erinnere, wird es vor jedem Test ausgeführt, der in "dieser" Testklasse definiert ist... Versuchen Sie setUpBeforeClass()

Desde http://www.phpunit.de/manual/3.4/en/fixtures.html

Darüber hinaus werden die Vorlagenmethoden setUpBeforeClass() und tearDownAfterClass() aufgerufen, bevor der erste Test der Testfallklasse ausgeführt wird bzw. nachdem der letzte Test der Testfallklasse ausgeführt wurde.

0voto

Jeff Lambert Punkte 23883

Hinzufügen meiner $.02 hier. Ich habe vor kurzem über diese gleiche Situation lief und nach einigen Frustration hier ist, wie ich in der Lage war, es zu lösen:

class MyTest extends PHPUnit_Framework_TestCase
    protected static $_soapMock = null;

    public function testDoWork_WillSucceed( )
    {
        $this->_worker->setClient( self::getSoapClient( $this ) );
        $result = $this->_worker->doWork( );
        $this->assertEquals( true, $result['success'] );
    }

    protected static function getSoapClient( $obj )
    {
        if( !self::$_soapMock ) {
            self::$_soapMock = $obj->getMockFromWsdl( 
                'Test/wsdl.xml', 'SoapClient_MyWorker'
            );
        }

        return self::$_soapMock;
    }
}

Ich habe viele "Worker", jeder in seiner eigenen Testklasse, von denen jeder Zugriff auf ein Mocked-SOAP-Objekt benötigt. Im zweiten Parameter von getMockFromWsdl Ich musste darauf achten, dass ich jedem einen eindeutigen Namen gebe (z. B. SoapClient_MyWorker ) oder es würde PHPUnit zum Absturz bringen.

Ich bin nicht sicher, ob das SOAP-Mock von einer statischen Funktion abgerufen wird und der Zugriff auf die getMockFromWsdl Funktion durch Übergabe von $this als Parameter ist der beste Weg, um dies zu erreichen, aber das war's auch schon.

0voto

b01 Punkte 3732

Eine Möglichkeit, ein Objekt von Test zu Test in PHPUnits weiterzugeben, ist die Testabhängigkeit, wenn die Instanziierung eines bestimmten Objekts zu anstrengend/zeitaufwendig ist:

<?php
/**
* Pass an object from test to test
*/
class WebSericeTest extends PHPUnit_Framework_TestCase
{

    protected function setUp() {
        parent::setUp();
        // I don't know enough about your test cases, and do not know
        // the implications of moving code out of your setup.
    }

    /**
    * First Test which creates the SoapClient mock object.
    */
    public function test1()
    {
        $this->client = new Client();

        $soapClient = $this->getMockFromWsdl(
            'service.wsdl'
        );

        $this->client->setClient($this->SoapClient);
        $this->markTestIncomplete();
        // To complete this test you could assert that the
        // soap client is set in the client object. Or
        // perform some other test of your choosing.

        return $soapClient;
    }

    /**
    * Second Test depends on web service mock object from the first test.
    * @depends test1
    */
    public function test1( $soapClient )
    {
        // you should now have the soap client returned from the first test.
        return $soapClient;
    }

    /**
    * Third Test depends on web service mock object from the first test.
    * @depends test1
    */
    public function test3( $soapClient )
    {
        // you should now have the soap client returned from the first test.
        return $soapClient;
    }
}
?>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X