2009-11-05 4 views
6

Sto provando a verificare se un metodo protetto viene chiamato in un'interfaccia pubblica.Verifica se è stato chiamato un metodo protetto

<?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(); 
    } 
} 

So che viene chiamato correttamente, ma PHPUnit dice che non è mai stato chiamato.

Lo stesso accade quando prova dall'altra parte, quando un metodo è mai chiamato:

<?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(); 
    } 
} 

Il metodo si chiama ma PHPUnit dice che non lo è.

Cosa sto facendo male?

Edit ho non't dichiarando i miei metodi con doppi due punti, è stato solo per denotare che si trattava di un metodo pubblico (interfaccia). Aggiornato a tutte le dichiarazioni di classe/metodi.

Edit 2 avrei dovuto dire che sto testando alcune implementazioni di metodo in una classe astratta (a cura del codice per riflettere questo). Dal momento che non riesco a creare un'istanza della classe, come posso testarla?

Sto pensando di creare un SomeClassSimple estendendo SomeClassAbstract e testarlo invece. È l'approccio giusto?

risposta

11

Nella versione di PHPUnit che ho, la classe PHPUnit_Framework_MockObject_Mock utilizza PHP get_class_methods per determinare l'interfaccia dell'oggetto che viene deriso. get_class_methods sceglierà solo i metodi pubblici, non quelli protetti o privati.

Questo è in linea con lo spirito del test dell'unità xUnit. Considera l'esempio dei documenti PHPUnit su come utilizzare Mock Objects. Lì, il SUT è Subject, che ha un metodo protetto notify. Il metodo testato, tuttavia, è doSomething. Considerando Subject come una scatola nera, non ci interessa i dettagli di come è implementato. Ci interessa, tuttavia, il suo comportamento . Nello specifico, richiediamo che quando chiamiamo doSomething, venga chiamato il metodo update di qualsiasi osservatore collegato. Quindi prendiamo in giro l'oggetto di terze parti Observer e configuriamo l'aspettativa che venga chiamato il suo metodo update. Si noti che, nonostante venga esercitato il metodo protetto notify, nel test non viene indicato esplicitamente. Questo ci dà la libertà di cambiare l'implementazione ogni volta che ci piace, purché il comportamento sia preservato.

Torna al tuo esempio.

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

    $mock->doStuff(); 
    } 
} 

Qui, il metodo di testCalled crea alcuna istanza di Test sistema sotto (SUT), che sarebbe SomeClass. La versione di doStuff nel modello di SomeClass nel non fa nulla. In particolare, non chiama _protectedMethod.

+0

Grazie Ewan, proprio tu sei.Naturalmente se si tratta di un oggetto fittizio non ha l'implementazione del metodo. Quanto muto io. Segnerò la tua risposta come corretta. Se puoi, per favore, vedi la mia seconda modifica. –

+0

Quindi quello che sto cercando di testare è l'implementazione, non il comportamento, giusto? È un po 'più chiaro per me, grazie. –

+2

L'analisi delle unità è, penso, più un'arte di quanto sembri. L'ho apprezzato di più dopo aver letto xUnit Test Patterns: Refactoring Test Code di Gerard Meszaros. A sua volta, il libro era una forte raccomandazione di Sebastian Bergmann, l'autore di PHPUnit. –

4

Sembra che avete semplicemente bisogno di dire a PHPUnit che si vuole prendere in giro che la funzione, cioè .:

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

$mock->doStuff();