2015-06-16 14 views
5

Sto provando a creare il mio primo test di phpunit e mi ritrovo a dover eseguire uno stub di un metodo su un'interfaccia IMailer.PHP Chiamata a un metodo non definito `Mock_x _ :: method()`

interface IMailer 
{ 
    public function send($to, $from, $cc, $subject, $body); 
    public function sent(); 
} 

    $mailer = $this->getMockBuilder(
     'IMailer', 
     array('send', 'sent'))->getMock(); 

    $mailer->method('send')->willRreturn(0); 

Tuttavia, continuo a ricevere

PHP Fatal error: 
    Call to undefined method Mock_Mailer_13fc0a04::method() 
    in ...Test.php on line 16 

un var_dump($mailer); risultati in

class Mock_IMailer_4c3e02a7#215 (1) { 
    private $__phpunit_invocationMocker => 
    NULL 
} 

Lavorare con la dà un errore di Dito - sembra che l'oggetto preso in giro non ha finto funzionalità ...

Sto eseguendo phpunit 3.7.28 e php 5.5.9, su una scatola di Ubuntu.

Come mai? Come posso ripararlo?

risposta

5

La funzione getMockBuilder accetta solo il parametro className come parametro. Il modo corretto per inizializzare i vostri metodi di un oggetto finto sarebbe quella di utilizzare la funzione setMethods (vedi phpunit docs)

$mailer = $this->getMockBuilder('IMailer') 
     ->setMethods(array('send', 'sent')) 
     ->getMock(); 

Inoltre probabilmente vuole avere qualche definizione aspetta anche quando si utilizza l'oggetto finto:

$mailer->expects($this->any()) 
     ->method('send') 
     ->willReturn(0); 

EDIT

Quanto sopra vale per le versioni di phpunità più recenti. Per phpunit 3.7.28 l'utilizzo dell'oggetto fittizio è un po 'diverso (ad esempio, l'attesa sembra essere obbligatoria e willReturn non è ancora disponibile). Per 3.7.28 versione è necessario modificare la seconda parte di:

$mailer->expects($this->any()) 
     ->method('send') 
     ->will($this->returnValue(0)); 

mi sento di raccomandare l'aggiornamento alla versione phpunit più tardi come sembra essere un po 'difficile da trovare la documentazione per questa release molto più antiche.

+0

Grazie per correggere il mio 'getMockBuilder' invocazione. Tuttavia, il "metodo non definito" rimane ... – xtofl

+0

Il codice sopra riportato funziona bene senza errori su phpunit 4.1.0.Hai provato ad aggiungere la chiamata di funzione prevista alla seconda parte ('$ mailer-> expect-> method-> willReturn')? Potresti condividere l'intera classe di test che stai utilizzando? Questo potrebbe dare qualche indizio in più sul problema che stai affrontando ... – ejuhjav

+1

Penso che questo dovrebbe essere accettato risposta. -> setMethods e -> returnValue ha risolto il mio problema molto simile (sembra che anch'io abbia una vecchia phpunit) – Jimmmy

0

Una soluzione alternativa, per chiunque usi ancora le vecchie versioni di PHPUnit, ma vuole comunque essere in grado di chiamare direttamente method(), è sovrascrivere il modello di classe oggetto di simulazione predefinito.

Copia MockObject/Generator/mocked_class.tpl.dist e denominare la copia mocked_class.tpl. Poi, basta aggiungere the code for the method() method al modello:

public function method() 
{ 
    $any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount; 
    $expects = $this->expects($any); 
    $args = func_get_args(); 
    return call_user_func_array(array($expects, 'method'), $args); 
} 

Questo vi permetterà di chiamare $mock->method() direttamente. Tuttavia, è necessario utilizzare ancora ->will($this->returnValue(0)) anziché ->willReturn(0). Per fare questo, è necessario introdurre un costruttore invocazione personalizzato e invocazione beffardo:

class My_MockObject_Builder_InvocationMocker 
    extends PHPUnit_Framework_MockObject_Builder_InvocationMocker { 

    public function willReturn($value) { 
     return $this->will(new PHPUnit_Framework_MockObject_Stub_Return($value)); 
    } 
} 

class My_MockObject_InvocationMocker 
    extends PHPUnit_Framework_MockObject_InvocationMocker { 

    public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) { 
     return new My_MockObject_Builder_InvocationMocker($this, $matcher); 
    } 
} 

e aggiornare il modello di nuovo, da utilizzare al posto di My_MockObject_InvocationMockerPHPUnit_Framework_MockObject_InvocationMocker.

Il modello completo sarebbe quindi simile a questa:

{prologue}{class_declaration} 
{ 
    protected static $staticInvocationMocker; 
    protected $invocationMocker; 

{clone}{mocked_methods} 
    public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) 
    { 
     return $this->__phpunit_getInvocationMocker()->expects($matcher); 
    } 

    public function method() 
    { 
     $any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount; 
     $expects = $this->expects($any); 
     $args = func_get_args(); 
     return call_user_func_array(array($expects, 'method'), $args); 
    } 

    public static function staticExpects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher) 
    { 
     return self::__phpunit_getStaticInvocationMocker()->expects($matcher); 
    } 

    public function __phpunit_getInvocationMocker() 
    { 
     if ($this->invocationMocker === NULL) { 
      $this->invocationMocker = new My_MockObject_InvocationMocker; 
     } 

     return $this->invocationMocker; 
    } 

    public static function __phpunit_getStaticInvocationMocker() 
    { 
     if (self::$staticInvocationMocker === NULL) { 
      self::$staticInvocationMocker = new My_MockObject_InvocationMocker; 
     } 

     return self::$staticInvocationMocker; 
    } 

    public function __phpunit_hasMatchers() 
    { 
     return self::__phpunit_getStaticInvocationMocker()->hasMatchers() || 
       $this->__phpunit_getInvocationMocker()->hasMatchers(); 
    } 

    public function __phpunit_verify() 
    { 
     self::__phpunit_getStaticInvocationMocker()->verify(); 
     $this->__phpunit_getInvocationMocker()->verify(); 
    } 

    public function __phpunit_cleanup() 
    { 
     self::$staticInvocationMocker = NULL; 
     $this->invocationMocker  = NULL; 
    } 
}{epilogue}