Como posso obter PHPUnit MockObjects para retornar valores diferentes com base em um parâmetro?

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

Pergunta

Eu tenho um objeto fictício PHPUnit que os retornos 'return value' não importa o que os seus argumentos:

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

O que eu quero ser capaz de fazer é retornar um valor diferente com base nos argumentos passados ??para o método de simulação. Eu tentei 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"'));

Mas isso faz com PHPUnit para reclamar se a simulação não é chamado com o 'two' argumento, assim que eu supor que a definição de methodToMock('two') substitui a definição do primeiro.

Então, minha pergunta é: Existe alguma maneira de obter um objeto PHPUnit simulada para retornar um valor diferente com base em seus argumentos? E se sim, como?

Foi útil?

Solução

Use uma chamada de retorno. por exemplo. (Em linha reta de documentação 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();
    // ...
}
?>

Faça o que o processamento que você quer no retorno de chamada () e retornar o resultado com base em suas $ args conforme o caso.

Outras dicas

Desde as últimas docs phpunit: "Às vezes um método stubbed deve retornar valores diferentes dependendo de uma lista predefinida de argumentos que você pode usar returnValueMap () para criar um mapa que associa argumentos com valores de retorno correspondente."

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

Eu tive um problema semelhante (embora ligeiramente diferente ... Eu não precisava valor de retorno diferente com base em argumentos, mas teve de teste para garantir 2 conjuntos de argumentos estavam sendo passados ??para a mesma função). Eu tropecei em cima de usar algo como isto:

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

Não é perfeito, uma vez que exige que a ordem dos 2 chamadas para foo () é conhecido, mas na prática isso provavelmente não é muito ruim.

Você provavelmente quer fazer uma chamada de retorno de forma 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];
    }
}
?>

Não é exatamente o que você pedir, mas em alguns casos isso pode ajudar:

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

onConsecutiveCalls - retorna uma lista de valores na ordem especificada

Passagem de nível dois de matriz, em que cada elemento é um conjunto de:

  • primeiros são parâmetros do método, e menos é o valor de retorno.

exemplo:

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

Você também pode retornar o argumento da seguinte forma:

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

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

Como você pode ver na Mocking documentação , o método returnValue($index) permite retornar o argumento dado.

Você algo dizer assim?

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

Eu tive um problema semelhante que eu não poderia trabalhar fora também (há surpreendentemente pouca informação sobre para PHPUnit). No meu caso, eu só fez cada teste teste separado - entrada conhecido e saída conhecido. Eu percebi que eu não tinha necessidade de fazer um jack-of-all-trades objeto fictício, eu só precisava de um específico para um teste específico, e, portanto, eu separei os testes fora e pode testar aspectos individuais do meu código como um separado unidade. Eu não tenho certeza se isso pode ser aplicável a você ou não, mas isso é para baixo para o que você precisa de teste.

$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'),


    }

Tente:

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top