2013-04-19 12 views
7

Jestem nowa w phpunit i przeczytałem dokumentację na próbnych obiektach, ale nie jest to bardzo jasne.Próby PHPUnit - metoda assert o nazwie

Próbuję napisać prosty test, który zapewnia, że ​​metoda w klasie jest wywoływana. Za pomocą poniższego kodu testuję, że po wywołaniu Client :: exchangeArray wywoływane jest wywołanie 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); 
    }   
} 

Oto mój przypadek testowy:

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

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

... a ja otrzymuję następujący błąd:

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.

Gdzie jestem będzie niewłaściwy?

Odpowiedz

9

Wszystko zależy od tego, co chcesz przetestować i co chcesz udawać. Bazując na nazwie twojego testu zakładam, że chcesz przetestować metodę exchangeArray.

Metoda getMock przyjmuje jako drugi argument nazwy metod, które chcesz sfałszować. Oznacza to, że nigdy nie zostaną powołani.

Tak więc, jeśli chcesz testowy exchangeArray sposób i makiety getInputFilter należy przekazać „getInputFilter” w drugim argumencie, jak poniżej:

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

Ale bądź ostrożny. Nie powiedziałeś ośmieszeniu, że możesz zwrócić wszystko, więc zwróci wartość pustą. Oznacza to, że dostaniesz błąd krytyczny w drugiej linii metody exchangeArray (próba wywołania metody na nieobiektowym). Należy przygotować jakieś sfałszowane obiektu filtra do czynienia, na przykład:

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

A jeśli chcesz wywołać „prawdziwy” getInputFilter metoda - to po prostu nie może drwić z tej metody.

+0

Dzięki za odpowiedź. Mam już implementacje dla obu metod. Chciałem tylko sprawdzić, czy metody zostały wywołane we właściwej kolejności, a następnie, że są wywoływane z określonymi parametrami. Czy istnieje sposób sprawdzenia, czy metody są wywoływane bez fałszywych obiektów? –

+0

Nie, nie ma. Ale jeśli chcesz wywołać drugą metodę, nie musisz sprawdzać, czy została ona rzeczywiście wywołana, bo jeśli nie, to nie otrzymasz obiektu $ inputFilter, a mimo to test zakończy się niepowodzeniem. – Cyprian

+1

Z drugiej strony, jeśli test przejdzie, a druga metoda nie zostanie wywołana (nie stanie się to w twoim przypadku, ale w niektórych przypadkach może), zauważysz to w raporcie pokrycia kodu. Może to oznaczać, że po prostu nie potrzebujesz tego drugiego połączenia LUB że naprawiłeś swoje testy. Jeśli twoja druga metoda ustawi jakąś wewnętrzną właściwość obiektu, możesz również przetestować tę właściwość, aby sprawdzić, czy metoda została wywołana. – Cyprian

Powiązane problemy