web-dev-qa-db-fra.com

Comment obtenir que PHPUnit MockObjects renvoie différentes valeurs en fonction d'un paramètre?

J'ai un objet fictif PHPUnit qui renvoie 'return value' Quel que soit son argument:

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

Ce que je veux pouvoir faire, c'est renvoyer une valeur différente en fonction des arguments passés à la méthode mock. J'ai essayé quelque chose comme:

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

Mais cela provoque PHPUnit à se plaindre si la maquette n'est pas appelée avec l'argument 'two', Alors je suppose que la définition de methodToMock('two') écrase la définition du premier.

Ma question est donc la suivante: existe-t-il un moyen de faire en sorte qu'un objet fictif PHPUnit renvoie une valeur différente en fonction de ses arguments? Et si oui, comment?

126
Ben Dowling

Utilisez un rappel. par exemple. (directement de la documentation PHPUnit):

<?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();
    // ...
}
?>

Faites le traitement que vous voulez dans le callback () et renvoyez le résultat en fonction de vos $ args selon le cas.

113
Howard Sandford

De la dernière documentation phpUnit: "Parfois, une méthode stubbed doit renvoyer des valeurs différentes selon une liste d'arguments prédéfinie. Vous pouvez utiliser returnValueMap () pour créer une mappe associant des arguments aux valeurs de retour correspondantes."

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

J'avais un problème similaire (bien que légèrement différent ... Je n'avais pas besoin d'une valeur de retour différente basée sur des arguments, mais je devais tester pour s'assurer que 2 jeux d'arguments étaient passés à la même fonction). Je suis tombé sur quelque chose comme ça:

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

Ce n'est pas parfait, car il faut connaître l'ordre des 2 appels à foo (), mais en pratique, ce n'est probablement pas aussi mauvais.

45
Adam

Vous voudrez probablement faire un rappel de manière OOP:

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

Ce n'est pas exactement ce que vous demandez, mais dans certains cas, cela peut aider:

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

onConsecutiveCalls - retourne une liste de valeurs dans l'ordre spécifié

14
Prokhor Sednev

Passez deux tableaux de niveau, où chaque élément est un tableau de:

  • sont d'abord les paramètres de la méthode, et le moins est la valeur de retour.

exemple:

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

Vous pouvez également renvoyer l'argument comme suit:

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

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

Comme vous pouvez le voir dans la documentation de Mocking , la méthode returnValue($index) permet de retourner l'argument donné.

2
Gabriel Gcia Fdez

J'ai eu un problème similaire que je ne pouvais pas résoudre aussi (il y a étonnamment peu d'informations sur PHPUnit). Dans mon cas, je viens de faire chaque test test séparé - entrée connue et sortie connue. J'ai réalisé que je n'avais pas besoin de créer un objet fictif touche-à-tout; je n'avais besoin que d'un objet spécifique pour un test spécifique. Ainsi, j'ai séparé les tests et je peux tester des aspects individuels de mon code séparément. unité. Je ne sais pas si cela pourrait vous concerner ou non, mais c'est ce que vous devez tester.

0
JamShady

Voulez-vous dire quelque chose comme ça?

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