2013-04-19 8 views
7

Sono nuovo di phpunit e ho letto la documentazione su oggetti finti ma non è molto chiaro.PHPUnit mocks - asser metodo chiamato

Sto provando a scrivere un semplice test che asserisce un metodo all'interno di una classe. Con il seguente codice, sto verificando che quando viene chiamato Client :: exchangeArray, viene effettuata una chiamata a Client :: getInputFilter.

class Client implements InputFilterAwareInterface 
{ 

public function getInputFilter() { 
    if(!$this->_inputFilter){ 
     $inputFactory = new InputFactory(); 
     $inputFilter = new InputFilter(); 

     $inputFilter->add($inputFactory->createInput(array(
      'name' => 'id', 
      'required' => true, 
      'filters' => array(
       array(
        'name' => 'Int' 
       ) 
      ) 
     ))); 

     $inputFilter->add($inputFactory->createInput(array(
      'name' => 'name', 
      'required' => true, 
      'filters' => array(
       array(
        'name' => 'StripTags' 
       ), 
       array(
        'name' => 'StringTrim' 
       ), 
       array(
        'name' => 'StripNewLines'  
       ), 
       array(
        'name' => 'Alpha' 
       ) 
      ), 
      'validators' => array(
       array(
        'name' => 'StringLength', 
        'options' => array(
         'encoding' => 'UTF-8', 
         'min' => 2, 
         'max' => 100 
        ) 
       ) 
      ) 
     ))); 

     $inputFilter->add($inputFactory->createInput(array(
      'name' => 'surname', 
      'required' => true, 
      'filters' => array(
       array(
        'name' => 'StripTags' 
       ), 
       array(
        'name' => 'StringTrim' 
       ) 
      ), 
      'validators' => array(
       array(
        'name' => 'StringLength', 
        'options' => array(
         'encoding' => 'UTF-8', 
         'min' => 2, 
         'max' => 100 
        ) 
       ) 
      ) 
     ))); 

     $inputFilter->add($inputFactory->createInput(array(
      'name' => 'email', 
      'required' => false, 
      'filters' => array(
       array(
        'name' => 'StripTags' 
       ), 
       array(
        'name' => 'StringTrim' 
       ) 
      ), 
      'validators' => array(
       array(
        'name' => 'StringLength', 
        'options' => array(
         'encoding' => 'UTF-8', 
         'min' => 2, 
         'max' => 150 
        ) 
       ), 
       array(
        'name' => 'EmailAddress' 
       ) 
      ) 
     ))); 

     $this->_inputFilter = $inputFilter; 
    } 
    return $this->_inputFilter; 
} 

public function exchangeArray($data){ 
    $inputFilter = $this->getInputFilter(); 
    $inputFilter->setData($data); 
    if(!$inputFilter->isValid()){ 
     throw new \Exception('Invalid client data'); 
    } 

    $cleanValues = $inputFilter->getValues(); 

    $this->_id = (isset($cleanValues['id']) ? $cleanValues['id'] : null); 
    $this->_name = (isset($cleanValues['name']) ? $cleanValues['name'] : null); 
    $this->_surname = (isset($cleanValues['surname']) ? $cleanValues['surname'] : null); 
    $this->_email = (isset($cleanValues['email']) ? $cleanValues['email'] : null); 
    }   
} 

Ecco il mio banco di prova:

public function testExchangeArrayCallsInputFilter(){ 
    $data = array('id' => 54, 
      'name' => 'john', 
      'surname' => 'doe', 
      'email' => '[email protected]domain.com' 
    ); 

    $mock = $this->getMock('Client', array('exchangeArray')); 
    $mock->expects($this->once()) 
     ->method('getInputFilter'); 
    $mock->exchangeArray($data); 
} 

... e sto ottenendo il seguente errore:

Expectation failed for method name is equal to when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times.

dove sto andando male?

risposta

9

Tutto dipende da ciò che si desidera testare e da ciò che si vuole simulare. In base al nome del test presumo che si desidera testare il metodo exchangeArray.

Il metodo getMock accetta come secondo argomento nomi di metodi che si desidera simulare. Significa che non saranno mai chiamati.

Quindi, se si vuole testare exchangeArray metodo e finto getInputFilter si dovrebbe passare "getInputFilter" nel secondo argomento, come di seguito:

$mock = $this->getMock('Client', array('getInputFilter')); 
$mock->expects($this->once()) 
    ->method('getInputFilter'); 
$mock->exchangeArray($data); 

Ma attenzione. Non hai detto al tuo mock di restituire nulla, quindi restituirà un valore nullo. Ciò significa che avrai un errore fatale sulla seconda riga del metodo exchangeArray (provando a chiamare il metodo su non-oggetto). Si dovrebbe preparare un oggetto filtro finto di affrontare, ad esempio:

// $preparedFilterObject = ... 
$mock = $this->getMock('Client', array('getInputFilter')); 
$mock->expects($this->once()) 
    ->method('getInputFilter') 
    ->will($this->returnValue($preparedFilterObject); 
$mock->exchangeArray($data); 

E se si desidera richiamare "reale" getInputFilter metodo - poi basta solo non può prendere in giro questo metodo.

+0

Grazie per la risposta. Ho già implementazioni per entrambi i metodi. Volevo solo verificare che i metodi venissero chiamati in un ordine corretto e quindi che venissero chiamati con parametri specifici. C'è un modo per verificare che i metodi vengano chiamati senza oggetti finti? –

+0

No, non c'è. Ma se si desidera chiamare il secondo metodo, non è necessario controllare se è stato effettivamente chiamato perché, in caso contrario, non si ottiene $ inputFilter e si verifica comunque un errore. – Cyprian

+1

D'altra parte se il tuo test ha superato e il secondo metodo non è stato chiamato (non succederà nel tuo caso, ma in alcuni casi potrebbe) noterai che sul rapporto di copertura del codice. E potrebbe significare che non hai bisogno di questa seconda chiamata O hai risolto i tuoi test. Nel caso in cui il secondo metodo imposta alcune proprietà dell'oggetto interno, è anche possibile testare questa proprietà, per verificare se il metodo è stato chiamato. – Cyprian