2013-01-04 20 views
5

Utilizzando PHPUnit e un oggetto fittizio, sto provando a testare del codice che utilizza get_class per determinare se un oggetto è incluso o meno da un filtro.Test del codice che utilizza get_class con PHPUnit oggetti fittizi

Qui è la classe da testare:

class BlockFilter implements FilterInterface 
{ 
    private $classes; 

    public function __construct(array $classes = array()) 
    { 
     $this->classes = $classes; 
    } 

    public function isIncluded(NodeTraversableInterface $node) 
    { 
     if (Type::BLOCK != $node->getDocumentType()) { 
      return false; 
     } 

     if (! empty($this->classes)) { 
      /*** HERE IS THE PROBLEM: ***/ 
      return in_array(get_class($node), $this->classes); 
     } 

     return true; 
    } 
} 

Ecco il metodo dal mio test di unità:

public function testIfContainerBlockIsIncluded() 
{ 
    $containerBlock = $this->getMock('Pwn\ContentBundle\Document\ContainerBlock'); 
    $containerBlock->expects($this->any())->method('getDocumentType')->will($this->returnValue(Type::BLOCK)); 

    $filter = new BlockFilter(array('Pwn\ContentBundle\Document\ContainerBlock')); 
    $this->assertTrue($filter->isIncluded($containerBlock)); 
} 

L'oggetto fittizio $containerBlock si comporta come l'oggetto reale Pwn\ContentBundle\Document\ContainerBlock; anche il codice che utilizza instanceof funziona (perché PHPUnit lo rende una sottoclasse della classe reale, credo).

Il codice in prova utilizza get_class per ottenere un valore di stringa della classe e confrontarlo con una matrice di nomi di classe previsti. Purtroppo, per l'oggetto finto, get_class restituisce qualcosa di simile:

Mock_ContainerBlock_ac231064 

(i _ac231064 cambiamenti suffisso su ogni chiamata).

Questo causa il mio test fallire, quindi quali sono le mie opzioni?

  • Rilanciare il codice per evitare l'uso di get_class? Questo implica che get_class non dovrebbe essere usato quando si tenta di scrivere codice testabile.
  • Utilizzare un'istanza reale della classe ContainerBlock anziché una simulazione? Ciò significa che stiamo testando efficacemente entrambe le classi contemporaneamente.
  • Qualche altro trucco incredibilmente intelligente che tutti suggerirai ??? ;)

Grazie per qualsiasi aiuto ...

risposta

2

passare il nome della classe del Mock nel test:

new BlockFilter(array(get_class($this->containerBlock))); 
+0

Buona idea, credo che questo era nella parte posteriore della mia mente in realtà, ma sembra rendere il test in qualche modo "artificiale"; Avrei meno probabilità di individuare un errore con il test stesso. Quindi ora mi chiedo se questo è meglio o peggio che usare oggetti reali invece di mock ... – fazy

+0

@LarsJ Non vedo alcun problema con quello. Il tuo BlockFilter sta testando i nomi delle classi nell'array, quindi passare il nome della classe di Mock è perfettamente a posto. Su un sidenote, mi piacerebbe prendere in giro l'interfaccia al posto del ContainerBlock, dal momento che questo è ciò che chiede il TypeHint su Inclusive. – Gordon

+1

Grazie ancora per tutti i vostri pensieri e commenti; L'ho messo in pratica e funziona bene. – fazy

Problemi correlati