2011-01-15 13 views
17

Voglio prendere in giro un metodo di una classe ed eseguire un callback che modifica l'oggetto dato come parametro (utilizzando PHP 5.3 con PHPUnit 3.5.5).Modifica oggetti in returnCallback() di PHPUnit Mocks

Mettiamoci dire che ho la seguente classe:

class A 
{ 
    function foobar($object) 
    { 
    doSomething(); 
    } 
} 

E questo codice di installazione:

$mock = $this->getMockBuilder('A')->getMock(); 
$mock->expects($this->any())->method('foobar')->will(
    $this->returnCallback(function($object) { 
    $object->property = something; 
    })); 

Per qualche motivo l'oggetto non viene modificato. Su var_dump ing $object vedo che è l'oggetto giusto. Potrebbe essere che l'oggetto venga passato per valore? Come posso configurare il mock per ricevere un riferimento?

risposta

39

Egli Alex,

ho parlato con Sebastian (il creatore phpunit) su questo problema e sì: L'argomento ottiene clone ndr prima di essere passato al callback.

Dall'alto della mia testa non posso offrirti alcuna soluzione, ma ho scelto di rispondere comunque almeno per dirti che non stai facendo nulla di sbagliato e che questo è un comportamento previsto.

citare Sebastians commento su IRC sul perché si clona l'argomento:

Si tratta di un lungo dibattito in corso tra me, me stesso, e gli utenti di PHPUnit se questo è giusto ;-)

Per avere qualcosa di copia/incollabile:

L'asserzione 3 in questo codice fallirà. (La variabile viene cambiato solo nell'oggetto restituito)

<?php 
class A 
{ 
    function foobar($o) 
    { 
     $o->x = mt_rand(5, 100); 
    } 
} 

class Test extends PHPUnit_Framework_TestCase 
{ 
    public function testFoo() 
    { 
     $mock = $this->getMock('A'); 
     $mock->expects($this->any()) 
      ->method('foobar') 
      ->will($this->returnCallback(function($o) { $o->x = 2; return $o; })); 

     $o = new StdClass; 
     $o->x = 1; 

     $this->assertEquals(1, $o->x); 
     $return = $mock->foobar($o); 

     $this->assertEquals(2, $return->x); 
     $this->assertEquals(2, $o->x); 
    } 
} 

Aggiornamento:

Partendo PHPUnit 3.7 clonazione può essere spento. Vedere l'ultimo argomento off:

public function getMock(
    $originalClassName, 
    $methods = array(), 
    array $arguments = array(), 
    $mockClassName = '', 
    $callOriginalConstructor = TRUE, 
    $callOriginalClone = TRUE, 
    $callAutoload = TRUE, 
    $cloneArguments = FALSE 
); 

Potrebbe anche essere disattivata per impostazione predefinita :)

+2

Grazie mille per questa risposta dettagliata e ben studiata! Anche se ora devo pensare ad un altro modo per testare la mia situazione, è bene sapere che questo è un comportamento previsto. –

5

La classe che esegue la clonazione dei parametri passati al metodo deriso è PHPUnit_Framework_MockObject_Invocation_Static. Guardando a cloneObject() puoi vedere che restituirà l'oggetto originale se il metodo __clone() della classe del parametro non è pubblico.

Se si ha il controllo sulla classe dei parametri oggetti e non è necessario clonare mai da soli, è possibile aggiungere un metodo privato vuoto __clone().

+0

Questo trucco non sembra molto bello, ma ha funzionato per me, grazie mille! –

Problemi correlati