2012-02-22 8 views
28

Quando eseguo il test unitario del mio codice php con PHPUnit, sto cercando di capire il modo giusto di prendere in giro un oggetto senza prendere in giro nessuno dei suoi metodi.Creare una simulazione in phpunit senza prendere in giro alcun metodo?

Il problema è che se non chiamo getMockBuilder()->setMethods(), tutti i metodi sull'oggetto verranno derisi e non posso chiamare il metodo che voglio testare; ma se I do chiama setMethods(), allora ho bisogno di dirgli quale metodo usare per deridere, ma non voglio affatto prendere in giro alcun metodo. Ma ho bisogno di creare il mock in modo da evitare di chiamare il costruttore nel mio test.

Ecco un esempio banale di un metodo che vorrei prova:

class Foobar 
{ 
    public function __construct() 
    { 
     // stuff happens here ... 
    } 

    public function myMethod($s) 
    { 
     // I want to test this 
     return (strlen($s) > 3); 
    } 
} 

potrei provare myMethod() con:

$obj = new Foobar(); 
$this->assertTrue($obj->myMethod('abcd')); 

Ma questo potrebbe chiamare il costruttore di Foobar, che non mi volere. Così, invece mi piacerebbe provare:

$obj = $this->getMockBuilder('Foobar')->disableOriginalConstructor()->getMock(); 
$this->assertTrue($obj->myMethod('abcd')); 

Ma chiamando getMockBuilder() senza utilizzare setMethods() si tradurrà in tutti i suoi metodi di essere derisi e ritorno nullo, quindi la mia chiamata a myMethod() restituirà nulla senza toccare il codice che ho intenzione di provare.

mia soluzione finora è stato questo:

$obj = $this->getMockBuilder('Foobar')->setMethods(array('none')) 
    ->disableOriginalConstructor()->getMock(); 
$this->assertTrue($obj->myMethod('abcd')); 

Ciò deridere un metodo chiamato 'none', che non esiste, ma PHPUnit non se ne cura. Lasciamo myMethod() sbloccato in modo che possa chiamarlo, e mi consentirà anche di disabilitare il costruttore in modo che non lo chiami. Perfezionare! Solo che sembra che barare debba specificare un nome di metodo che non esiste - "nessuno", o "blargh" o "xyzzy".

Quale sarebbe il modo giusto per farlo?

risposta

38

È possibile passare null a setMethods() per evitare di prendere in giro qualsiasi metodo. Passare un array vuoto può prendere in giro tutti i metodi. Quest'ultimo è il valore predefinito per i metodi che hai trovato.

Detto questo, direi che la necessità di fare questo potrebbe indicare un difetto nel design di questa classe. Questo metodo dovrebbe essere statico o spostato in un'altra classe? Se il metodo non richiede un'istanza completamente costruita, è un segno per me che potrebbe essere un metodo di utilità che potrebbe essere reso statico.

+3

Grazie mille! Sembra che setMethods (null) sia quello che voglio; questo non causa alcun metodo per essere deriso. setMethods (array()), d'altra parte, sembra causare la derisione di tutti i metodi, come non usare setMethods(). Non ho potuto trovare questo documentato ovunque. Cosa intendi per "genitori vuoti"? –

+0

Inoltre, sono perplesso dal tuo commento. A parte le specifiche del banale esempio myMethod() che ho fornito sopra, perché un metodo che deve essere testato in questo modo ti fa sentire che il metodo dovrebbe essere spostato su un'altra classe o reso statico? –

+0

@BrianKendig - Errore di correzione automatica su "genitori" che dovrebbero essere "parenti". :) Ho appena controllato il codice sorgente e non ci sono impostazioni predefinite, quindi devi passare in 'null' da solo. –

3

Un'altra soluzione hacky, ma succinta è semplicemente quello di elencare il costruttore di magia come uno dei metodi deriso:

$mock = $this->getMock('MyClass', array('__construct')); 
-8

Questo ha funzionato per me:

$this->getMock($class, array(), array(), '', false); 
+0

Il punto viene perso completamente – dVaffection

0

Oppure si può semplicemente utilizzare getMock() direttamente .

$mock = $this->getMock('MyClass', null, array(), null, false);

+0

getMock() è deprecato – krazyweb

+0

Sì. Ho votato per la risposta accettata. – Ryan

Problemi correlati