Używając PHPUnit i obiektu próbnego, próbuję przetestować kod, który używa get_class
, aby określić, czy obiekt jest zawarty w filtrze, czy nie.Testowanie kodu, który używa get_class z PHPUnit mock objects
Oto klasy powinien być badany:
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;
}
}
Oto metoda z mojego badanej jednostki:
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));
}
makiety obiektów $containerBlock
zachowuje się jak prawdziwy obiekt Pwn\ContentBundle\Document\ContainerBlock
; nawet kod przy użyciu instanceof
działa (ponieważ PHPUnit sprawia, że jest to podklasa prawdziwej klasy, jak sądzę).
Testowany kod używa get_class
, aby uzyskać wartość łańcuchową klasy i porównać ją z tablicą oczekiwanych nazw klas. Niestety, dla atrapa obiektu, get_class zwraca coś takiego:
Mock_ContainerBlock_ac231064
(the _ac231064 przyrostek zmian na każdym wywołaniu).
Powoduje to niepowodzenie mojego testu, więc jakie są moje opcje?
- Przerób kod, aby uniknąć używania get_class? Oznacza to, że get_class nie powinien być używany podczas próby napisania testowalnego kodu.
- Użyj prawdziwej instancji klasy ContainerBlock zamiast makiety? Oznacza to, że efektywnie testujemy obie klasy jednocześnie.
- Jakiś inny niesamowicie sprytny trik, który wszyscy zamierzacie zasugerować ??? ;)
dzięki za pomoc ...
Dobry pomysł, myślę, że to było w mojej głowie, ale to faktycznie wydaje się, że test jest jakoś "sztuczny"; Byłbym mniej skłonny do zauważenia błędu w samym teście. Więc zastanawiam się, czy to jest lepsze, czy gorsze niż używanie prawdziwych obiektów zamiast makiet ... – fazy
@LarsJ Nie widzę żadnego problemu z tym. Twój BlockFilter testuje nazwy klas w tablicy, więc podanie nazwy klasy Mock jest całkowicie w porządku. W tym przewodniku wykpilam interfejs zamiast ContainerBlock, ponieważ o to pyta TypeHint on isIncluded. – Gordon
Jeszcze raz dziękuję za wszystkie twoje myśli i komentarze; Zastosowałem to w praktyce i działa dobrze. – fazy