2009-11-05 17 views
6

Próbuję sprawdzić, czy metoda chroniona jest wywoływana w interfejsie publicznym.Testowanie, czy chroniona metoda została nazwana

<?php 
abstract class SomeClassAbstract 
{ 
    abstract public foo(); 

    public function doStuff() 
    {  
     $this->_protectedMethod(); 
    } 

    protected function _protectedMethod(); 
    { 
     // implementation is irrelevant 
    } 
} 

<?php 
class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
     $mock = $this->getMockForAbstractClass('SomeClass'); 
     $mock->expects($this->once()) 
      ->method('_protectedMethod'); 

     $mock->doStuff(); 
    } 
} 

wiem, że nazywa się poprawnie, ale PHPUnit mówi jej nie nazwał.

To samo dzieje się, kiedy przetestować inny sposób, gdy metoda jest nigdy nazywa:

<?php 
abstract class AnotherClassAbstract 
{ 
    abstract public foo(); 

    public function doAnotherStuff() 
    {  
     $this->_loadCache(); 
    } 

    protected function _loadCache(); 
    { 
     // implementation is irrelevant 
    } 
} 

<?php 
class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
     $mock = $this->getMockForAbstractClass('AnotherClass'); 
     $mock->expects($this->once()) 
      ->method('_loadCache'); 

     $mock->doAnotherStuff(); 
    } 
} 

Metoda nazywa ale PHPUnit mówi, że tak nie jest.

Co robię źle?

Edit nie byłem deklarując moje metody z podwójnym dwukropkiem, to było po prostu za oznaczający, że była to metoda publicznego (interfejs). Zaktualizowano do pełnych deklaracji klasy/metod.

Edycja 2 powinienem powiedzieć, że jestem testowania niektóre implementacje metod w abstrakcyjne klasy (edytowany kod zastanowienia się tego). Ponieważ nie mogę utworzyć instancji klasy, jak mogę to przetestować?

Zastanawiam się nad stworzeniem SomeClassSimple przedłużania SomeClassAbstract i testowanie tego zamiast. Czy to właściwe podejście?

Odpowiedz

11

W wersji PHPUnit, którą posiadam, klasa PHPUnit_Framework_MockObject_Mock używa PHP get_class_methods do określenia interfejsu kpiącego obiektu. get_class_methods wybierze tylko metody publiczne, a nie chronione lub prywatne.

Jest to zgodne z duchem testów jednostkowych xUnit. Rozważ przykładowy dokument PHPUnit dotyczący używania Mock Objects. Tam SUT to Subject, który ma chronioną metodę notify. Testowana metoda to jednak doSomething. Biorąc pod uwagę Subject jako czarną skrzynkę, nie dbamy o szczegóły tego, jak jest ona zaimplementowana. Dbamy jednak o jego zachowanie w postaci . W szczególności wymagamy, aby wywołując metodę doSomething, wywoływano metodę update każdego dołączonego obserwatora. Więc kpimy z obiektu strony trzeciej Observer i ustalamy oczekiwanie, że zostanie wywołana jego metoda update. Zauważ, że pomimo użycia chronionej metody, nie jest ona jawnie wymieniona w teście. Daje nam to możliwość zmiany implementacji w dowolnym momencie, o ile zachowanie jest zachowane.

Powracanie do przykładu.

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
    $mock = $this->getMock('SomeClass'); 
    $mock->expects($this->once()) 
     ->method('_protectedMethod'); 

    $mock->doStuff(); 
    } 
} 

Tutaj metoda testCalled nie tworzy instancję Under System Testów (SUT), która byłaby SomeClass. Wersja doStuff w mock z SomeClass nic nie robi. W szczególności nie nazywa się _protectedMethod.

+0

dziękuję Ewan, Masz rację.Oczywiście, jeśli jest to fałszywy obiekt, nie ma implementacji metody. Jak głupi jestem. Zaznaczę twoją odpowiedź jako poprawną. Jeśli możesz, proszę, zobacz moją drugą edycję. –

+0

To, co próbuję przetestować, to implementacja, a nie zachowanie, prawda? To dla mnie trochę bardziej oczywiste, dziękuję. –

+2

Testowanie jednostek jest, jak sądzę, bardziej sztuką niż się wydaje. Doceniam to jeszcze bardziej po przeczytaniu wzorów testowych xUnit: Kod testowy refaktoryzacji Gerarda Meszarosa. Z kolei książka była silną rekomendacją Sebastiana Bergmanna, autora PHPUnit. –

4

To wygląda po prostu trzeba powiedzieć PHPUnit który chcesz szydzić z tej funkcji, tj .:

$mock = $this->getMock('SomeClass', 
         array('_protectedMethod')); 
$mock->expects($this->once()) 
    ->method('_protectedMethod'); 

$mock->doStuff(); 
Powiązane problemy