it-swarm.com.de

Wie kann ich PHPUnit MockObjects dazu bringen, unterschiedliche Werte basierend auf einem Parameter zurückzugeben?

Ich habe ein PHPUnit-Mock-Objekt, das unabhängig von den Argumenten 'return value' Zurückgibt:

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
     ->method('methodToMock')
     ->will($this->returnValue('return value'));

Ich möchte in der Lage sein, einen anderen Wert basierend auf den an die Mock-Methode übergebenen Argumenten zurückzugeben. Ich habe versucht, etwas wie:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('one'))
     ->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('two'))
     ->will($this->returnValue('method called with argument "two"'));

Dies führt jedoch dazu, dass PHPUnit sich beschwert, wenn der Mock nicht mit dem Argument 'two' Aufgerufen wird. Daher gehe ich davon aus, dass die Definition von methodToMock('two') die Definition der ersten überschreibt.

Meine Frage lautet also: Gibt es eine Möglichkeit, ein PHPUnit-Mock-Objekt dazu zu bringen, basierend auf seinen Argumenten einen anderen Wert zurückzugeben? Und wenn ja, wie?

126
Ben Dowling

Verwenden Sie einen Rückruf. z.B. (direkt aus der PHPUnit-Dokumentation):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

Führen Sie die im callback () gewünschte Verarbeitung durch und geben Sie das Ergebnis entsprechend Ihren $ args zurück.

113
Howard Sandford

Aus den neuesten phpUnit-Dokumenten: "Manchmal sollte eine Stubbed-Methode abhängig von einer vordefinierten Liste von Argumenten unterschiedliche Werte zurückgeben. Sie können returnValueMap () verwenden, um eine Map zu erstellen, die Argumente mit entsprechenden Rückgabewerten verknüpft."

$mock->expects($this->any())
    ->method('getConfigValue')
    ->will(
        $this->returnValueMap(
            array(
                array('firstparam', 'secondparam', 'retval'),
                array('modes', 'foo', array('Array', 'of', 'modes'))
            )
        )
    );
102

Ich hatte ein ähnliches Problem (obwohl etwas anders ... Ich brauchte keinen anderen Rückgabewert basierend auf Argumenten, musste aber testen, um sicherzustellen, dass 2 Sätze von Argumenten an dieselbe Funktion übergeben wurden). Ich bin auf so etwas gestoßen:

$mock = $this->getMock();
$mock->expects($this->at(0))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

$mock->expects($this->at(1))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

Es ist nicht perfekt, da es erfordert, dass die Reihenfolge der 2 Aufrufe von foo () bekannt ist, aber in der Praxis ist dies wahrscheinlich nicht z schlecht.

45
Adam

Sie möchten wahrscheinlich einen Rückruf in einer OOP Weise durchführen:

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnAction()
    {
        $object = $this->getMock('class_name', array('method_to_mock'));
        $object->expects($this->any())
            ->method('method_to_mock')
            ->will($this->returnCallback(array($this, 'returnCallback'));

        $object->returnAction('param1');
        // assert what param1 should return here

        $object->returnAction('param2');
        // assert what param2 should return here
    }

    public function returnCallback()
    {
        $args = func_get_args();

        // process $args[0] here and return the data you want to mock
        return 'The parameter was ' . $args[0];
    }
}
?>
26
Francis Lewis

Es ist nicht genau das, wonach Sie fragen, aber in einigen Fällen kann es helfen:

$mock->expects( $this->any() ) )
 ->method( 'methodToMock' )
 ->will( $this->onConsecutiveCalls( 'one', 'two' ) );

onConsecutiveCalls - gibt eine Liste von Werten in der angegebenen Reihenfolge zurück

14
Prokhor Sednev

Übergeben Sie ein Array mit zwei Ebenen, wobei jedes Element ein Array aus folgenden Elementen ist:

  • das erste sind Methodenparameter und das letzte ist der Rückgabewert.

beispiel:

->willReturnMap([
    ['firstArg', 'secondArg', 'returnValue']
])
3
antonmarin

Sie können das Argument auch wie folgt zurückgeben:

$stub = $this->getMock(
  'SomeClass', array('doSomething')
);

$stub->expects($this->any())
     ->method('doSomething')
     ->will($this->returnArgument(0));

Wie Sie in der Verspottungsdokumentation sehen können, erlaubt die Methode returnValue($index), das angegebene Argument zurückzugeben.

2

Ich hatte ein ähnliches Problem, das ich nicht so gut lösen konnte (es gibt überraschend wenig Informationen über PHPUnit). In meinem Fall habe ich nur jeden Test separat durchgeführt - bekannte Eingabe und bekannte Ausgabe. Mir wurde klar, dass ich kein Allround-Mock-Objekt erstellen musste, sondern nur ein bestimmtes für einen bestimmten Test benötigte. Auf diese Weise habe ich die Tests getrennt und kann einzelne Aspekte meines Codes separat testen Einheit. Ich bin mir nicht sicher, ob dies auf Sie zutrifft oder nicht, aber das hängt davon ab, was Sie testen müssen.

0
JamShady

Meinen Sie so etwas?

public function TestSomeCondition($condition){
  $mockObj = $this->getMockObject();
  $mockObj->setReturnValue('yourMethod',$condition);
}
0
eddy147