2015-06-16 6 views
5

Ich versuche, meinen ersten phpunit Test zu erstellen und finde mich selbst müssen eine Methode auf eine IMailer Schnittstelle Stub.PHPUnit Aufruf zu undefinierter Methode `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); 

Allerdings halte ich in

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

Arbeiten mit dem gibt einen dito Fehler

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

ein var_dump($mailer); Ergebnisse zu erzielen - es scheint, dass die nachgeahmten Objekt jede Mock nicht haben Funktionalität ...

Ich benutze phpunit 3.7.28, und php 5.5.9, auf einer Ubuntu-Box.

Wie kommt es? Wie kann ich es reparieren?

Antwort

5

Die getMockBuilder-Funktion akzeptiert nur den Klassennamen als Parameter. Der richtige Weg, um Ihre Mock-Objekt Methoden zu initialisieren wäre setMethods Funktion (siehe phpunit docs)

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

Zusätzlich wahrscheinlich verwenden Sie auch einige erwartet Definition haben wollen, wenn Sie Ihr Mock-Objekt verwenden:

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

EDIT

Das obige gilt für neuere phpunit-Versionen. Für phpunit 3.7.28 ist die Verwendung des Mock-Objekts etwas anders (d. H. Die erwarteten Daten scheinen obligatorisch zu sein, und es ist noch nicht verfügbar). Für 3.7.28 Version sollten Sie den zweiten Teil ändern:

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

würde ich die Aktualisierung später phpunit Version empfehlen, da es etwas schwierig zu sein scheint Dokumentation zu dieser viel älteren Versionen zu finden.

+0

Dank für meinen 'getMockBuilder' Aufruf zu korrigieren. Die 'undefined Methode' bleibt jedoch ... – xtofl

+0

Der obige Code läuft einwandfrei auf phpunit 4.1.0.Haben Sie versucht, den Funktionsaufruf expects zum zweiten Teil hinzuzufügen ('$ mailer -> expects-> method-> willReturn')? Können Sie die gesamte Testklasse teilen, die Sie ausführen? Das könnte Ihnen weitere Anhaltspunkte für das Problem geben, dem Sie gegenüberstehen ... – ejuhjav

+1

Ich denke, das sollte akzeptiert werden. -> setMethods und -> returnValue löste mein sehr ähnliches Problem (auch scheint es, ich habe alte phpunit) – Jimmmy

0

Eine alternative Lösung für alle, die immer noch alte PHPUnit-Versionen verwenden, aber trotzdem method() direkt aufrufen können, ist das Überschreiben der Standard-Mock-Objektklassenvorlage.

Kopieren Sie MockObject/Generator/mocked_class.tpl.dist, und nennen Sie die Kopie mocked_class.tpl. Dann fügen Sie einfach the code for the method() method der Vorlage:

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

Dies ermöglicht es Ihnen $mock->method() direkt anrufen. Sie müssen jedoch weiterhin ->will($this->returnValue(0)) anstelle von ->willReturn(0) verwenden. Um das zu tun, müssen Sie einen benutzerdefinierten Aufruf Builder und Aufruf Spötter vorstellen:

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

und aktualisieren Sie Ihre Vorlage erneut zu verwenden My_MockObject_InvocationMocker statt PHPUnit_Framework_MockObject_InvocationMocker.

Die vollständige Vorlage würde dann wie folgt aussehen:

{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}