¿Cómo puedo hacer que PHPUnit MockObjects devuelva diferentes valores basados ??en un parámetro?

StackOverflow https://stackoverflow.com/questions/277914

Pregunta

Tengo un objeto simulado PHPUnit que devuelve 'valor devuelto' sin importar sus argumentos:

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

Lo que quiero poder hacer es devolver un valor diferente basado en los argumentos pasados ??al método simulado. He intentado algo como:

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

Pero esto hace que PHPUnit se queje si el simulacro no se llama con el argumento 'two' , por lo que supongo que la definición de methodToMock ('two') sobrescribe la definición de la primera.

Entonces, mi pregunta es: ¿Hay alguna forma de obtener un objeto simulado PHPUnit para devolver un valor diferente en función de sus argumentos? Y si es así, ¿cómo?

¿Fue útil?

Solución

Use una devolución de llamada. p.ej. (directamente de la documentación de 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();
    // ...
}
?>

Realice el procesamiento que desee en la devolución de llamada () y devuelva el resultado según sus $ args según corresponda.

Otros consejos

De los últimos documentos de phpUnit: " A veces, un método con código auxiliar debería devolver valores diferentes según una lista predefinida de argumentos. Puede usar returnValueMap () para crear un mapa que asocie argumentos con los valores de retorno correspondientes. "

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

Tuve un problema similar (aunque ligeramente diferente ... No necesitaba un valor de retorno diferente en función de los argumentos, pero tuve que probar para asegurarme de que se pasaran 2 conjuntos de argumentos a la misma función). Me topé con algo como esto:

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

No es perfecto, ya que requiere que se conozca el orden de las 2 llamadas a foo (), pero en la práctica esto probablemente no sea demasiado malo.

Probablemente desee hacer una devolución de llamada de una manera 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];
    }
}
?>

No es exactamente lo que pides, pero en algunos casos puede ayudar:

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

onConsecutivoCalls - devuelve una lista de valores en el orden especificado

Pase una matriz de dos niveles, donde cada elemento es una matriz de:

  • primero son los parámetros del método, y el mínimo es el valor de retorno.

ejemplo:

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

También puede devolver el argumento de la siguiente manera:

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

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

Como puede ver en la Documentación de burla , el método returnValue ($ index) permite devolver el argumento dado.

¿Te refieres a algo como esto?

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

Tuve un problema similar que no pude resolver también (sorprendentemente hay poca información sobre PHPUnit). En mi caso, acabo de hacer cada prueba por separado: entrada conocida y salida conocida. Me di cuenta de que no necesitaba hacer un objeto simulado de Jack-of-All-Trades, solo necesitaba uno específico para una prueba específica y, por lo tanto, separé las pruebas y puedo probar aspectos individuales de mi código como un separado unidad. No estoy seguro de si esto podría ser aplicable a usted o no, pero eso depende de lo que necesite probar.

$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');

    public function testBusiness()
    {
        /*
            onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
        */
        $this->BusinessMock ->method('getEmployees')
                                ->will($this->onConsecutiveCalls(
                                            $this->returnArgument(0),
                                            $this->returnValue('employee')                                      
                                            )
                                      );
        // first call

        $this->assertInstanceOf( //$this->returnArgument(0),
                'argument',
                $this->BusinessMock->getEmployees()
                );
       // second call


        $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
      //$this->returnValue('employee'),


    }

Prueba:

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top