Come posso ottenere PHPUnit MockObjects per restituire valori diversi in base a un parametro?
-
07-07-2019 - |
Domanda
Ho un oggetto simulato PHPUnit che restituisce 'return value'
indipendentemente dai suoi argomenti:
// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
->method('methodToMock')
->will($this->returnValue('return value'));
Quello che voglio poter fare è restituire un valore diverso in base agli argomenti passati al metodo simulato. Ho provato qualcosa del tipo:
$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"'));
Ma questo fa sì che PHPUnit si lamenti se il mock non viene chiamato con l'argomento 'two'
, quindi presumo che la definizione di methodToMock ('two')
sovrascrive la definizione del primo.
Quindi la mia domanda è: c'è un modo per ottenere un oggetto simulato PHPUnit per restituire un valore diverso in base ai suoi argomenti? E se sì, come?
Soluzione
Usa un callback. per esempio. (direttamente dalla documentazione di 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();
// ...
}
?>
Esegui qualsiasi elaborazione tu voglia nel callback () e restituisci il risultato in base ai tuoi $ args come appropriato.
Altri suggerimenti
Dagli ultimi documenti phpUnit: " A volte un metodo stubbed dovrebbe restituire valori diversi a seconda di un elenco predefinito di argomenti. Puoi utilizzare returnValueMap () per creare una mappa che associa gli argomenti ai corrispondenti valori di ritorno. "
$mock->expects($this->any())
->method('getConfigValue')
->will(
$this->returnValueMap(
array(
array('firstparam', 'secondparam', 'retval'),
array('modes', 'foo', array('Array', 'of', 'modes'))
)
)
);
Ho avuto un problema simile (anche se leggermente diverso ... Non avevo bisogno di un valore di ritorno diverso basato su argomenti, ma ho dovuto testare per assicurarsi che 2 set di argomenti fossero passati alla stessa funzione). Mi sono imbattuto nell'usare qualcosa del genere:
$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(...));
Non è perfetto, poiché richiede che l'ordine delle 2 chiamate a foo () sia noto, ma in pratica questo probabilmente non è troppo cattivo.
Probabilmente vorresti fare una richiamata in modo 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];
}
}
?>
Non è esattamente quello che chiedi, ma in alcuni casi può aiutare:
$mock->expects( $this->any() ) )
->method( 'methodToMock' )
->will( $this->onConsecutiveCalls( 'one', 'two' ) );
onConsecutiveCalls - restituisce un elenco di valori nell'ordine specificato
Passa un array a due livelli, dove ogni elemento è un array di:
- innanzitutto sono i parametri del metodo e il meno è il valore restituito.
Esempio:
->willReturnMap([
['firstArg', 'secondArg', 'returnValue']
])
Puoi anche restituire l'argomento come segue:
$stub = $this->getMock(
'SomeClass', array('doSomething')
);
$stub->expects($this->any())
->method('doSomething')
->will($this->returnArgument(0));
Come puoi vedere nella Documentazione beffarda , il metodo returnValue ($ index)
consente di restituire l'argomento dato.
Intendi qualcosa del genere?
public function TestSomeCondition($condition){
$mockObj = $this->getMockObject();
$mockObj->setReturnValue('yourMethod',$condition);
}
Ho avuto un problema simile che non riuscivo a risolvere (ci sono sorprendentemente poche informazioni su PHPUnit). Nel mio caso, ho appena fatto ogni test separato test - input noto e output noto. Mi sono reso conto che non avevo bisogno di creare un oggetto fittizio tuttofare, ne avevo solo bisogno per uno specifico per un test specifico, quindi ho separato i test e posso testare singoli aspetti del mio codice come separato unità. Non sono sicuro che questo possa essere applicabile a te o no, ma dipende da ciò che devi testare.
$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'),
}
Prova:
->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));