2017-09-22 3 views
0

Ich mache eine PHPUnit auf meinem Controller und ich kann nicht scheinen, die Anfrage richtig zu verspotten.Laravel PHPUnit Mock Anfrage

Hier ist der Controller:

use Illuminate\Http\Request; 

public function insert(Request $request) 
{ 
    // ... some codes here 
    if ($request->has('username')) { 
     $userEmail = $request->get('username'); 
    } else if ($request->has('email')) { 
     $userEmail = $request->get('email'); 
    } 
    // ... some codes here 
} 

Dann auf dem Gerät zu testen,

public function testIndex() 
{ 
    // ... some codes here 

    $requestParams = [ 
     'username' => 'test', 
     'email' => '[email protected]' 
    ]; 

    $request = $this->getMockBuilder('Illuminate\Http\Request') 
     ->disableOriginalConstructor() 
     ->setMethods(['getMethod', 'retrieveItem', 'getRealMethod', 'all', 'getInputSource', 'get', 'has']) 
     ->getMock(); 

    $request->expects($this->any()) 
     ->method('get') 
     ->willReturn($requestParams); 

    $request->expects($this->any()) 
     ->method('has') 
     ->willReturn($requestParams); 

    $request->expects($this->any()) 
     ->method('all') 
     ->willReturn($requestParams); 

    // ... some codes here 
} 

Das Problem hier ist, dass, wann immer ich es immer gibt den $requestParams Wert var_dump($request->has('username');, in dem das gesamte Array ist. Ich erwarte, dass es true zurückgeben sollte, da der Benutzername-Schlüssel in dem Array vorhanden ist.

Dann, wenn ich den Benutzernamen Taste auf der $requestParams löschen, sollte es false zurück, da es nicht die username Schlüssel auf dem Array

Antwort

1

Was enthält, wie ich sehen und verstehen können Sie Ihr Gerät zu testen sind zu sagen, dass Wenn Sie $ request-> has() für Ihr Anforderungsobjekt aufrufen, sollte es das Array $ requestParams zurückgeben, nicht wahr oder falsch oder irgendetwas anderes.

Wenn Sie nicht speziell überprüfen, was mit einem Methodenaufruf gesendet wird, interessiert sich Ihr Mock eigentlich nicht dafür, was gesendet wird, es interessiert nur, dass es aufgerufen wurde.

Vielleicht möchten Sie eine leere Anfrage erstellen und sie mit Daten füllen, wenn dies in Ihrem Anwendungsfall möglich ist, da Sie damit den Komponententest einfacher und weniger problematisch durchführen können. Dies wird nicht in allen Fällen funktionieren.

Sie könnten angeben, welche Aussagen Sie in Ihrem Komponententest machen, damit wir klarer sehen, in was Sie hineinlaufen, aber so wie es ist. Es gibt genau das zurück, was Sie sagen, dass es zurückkehren soll. Auch wenn das nicht das ist, was Sie eigentlich wollen, dass es zurückkehrt.

Mocks werden verwendet, um Ihren Unit-Test vom Rest Ihres Systems zu trennen. Daher tendieren Sie normalerweise dazu, nur zu prüfen, ob eine bestimmte Methode aufgerufen wird, um zu sehen, ob Ihr Code tatsächlich in die Klasse übergeht, die Sie verspottet haben, und ob er die erwarteten Daten enthält, die Sie mitschicken würden. In einigen extremen Fällen können Sie sich über das System lustig machen, das Sie gerade testen, aber das bedeutet normalerweise, dass Ihr Code zu stark von anderen Klassen abhängig ist oder zu viel tut.

Ein weiterer Grund für die Verwendung von Mocks besteht darin, den Typumwandlungseinschränkungen in Ihren Methodenaufrufen zu entsprechen. In diesen Fällen erstellen Sie normalerweise ein leeres verspottetes Objekt und füllen es mit einigen Dummy-Daten, die Ihr Code akzeptiert oder unterbricht, um den Code zu testen.

In Ihrem Fall scheint es, dass Sie überprüfen möchten, ob Ihr Code tatsächlich richtig funktioniert und dafür würde ich vorschlagen, entweder die Anfrage nicht zu verspotten, oder spezifische Tests, bei denen Sie sagen, dass sie wahr oder falsch (Test für beide) Fälle)

So etwas entlang der Linien von:

$request->expects($this->any()) 
    ->method('has') 
    ->with('username') 
    ->willReturn(true); // or false in your next test 

Edit: Wie Sie im Kommentar erwähnt Weiter unten finden Sie in der Ausgabe lief, die Sie verwenden die Methode mehrfach im Code hat und lief in Probleme.

Die Fragen, die ich in meinem Antwortkommentar verlinkt habe, gehen näher, aber um es zusammenzufassen, können Sie eine Inline-Funktion oder die At() -Methode verwenden, um mehrere Fälle zu behandeln.

Mit at() können Sie bestimmte Iterationen des Codes angeben, um nur dieses Bit des Tests zu treffen.Es wurde erwähnt, dass dies Ihre Tests ziemlich brüchig macht, wie es vor den vorherigen Tests hinzugefügt wurde.

$request->expects($this->at(0)) 
    ->method('has') 
    ->with('username') 
    ->willReturn('returnValue'); 

$request->expects($this->at(1)) 
    ->method('has') 
    ->with('email') 
    ->willReturn('otherReturnValue'); 

Die Inline-Funktion (Callback) Lösung würde es ermöglichen Sie Ihren Test anpassen, dass mehrere Fälle zu ermöglichen und Daten zurückzukehren, wie erforderlich. Leider bin ich mit diesem Konzept nicht so vertraut, da ich es vorher nicht selbst benutzt habe. Ich empfehle das Lesen der PHPUnit docs für weitere Informationen dazu.

Am Ende würde ich vorschlagen, die Anfrage nicht zu verspotten und stattdessen eine leere Anfrage, dass Sie mit den Daten, die Sie überprüfen möchten, füllen. Laravel bietet einige beeindruckende Methoden, mit denen Sie die Anfrage manuell mit vielen Daten füllen können, gegen die Sie normalerweise testen würden.

Zum Beispiel können Sie Daten (Post/get-Daten) hinzufügen, indem

request->add(['fieldname' => 'value']) 

Als letzten paar Hinweise mit Ich mag würde zu erwähnen, dass es Sie var_dump verwenden scheint. Laravel kommt mit zwei eigenen Funktionen, die ähnlich und recht nützlich beim Debuggen sind. Sie können dd(); oder dump(); dd(); Dumps und stoppt die Ausführung von Code, während dump(); nur ausgibt, was Sie entscheiden. so könnten Sie dd($request); oder dump($request); tun und sehen, was die Variablen/Klassenobjekte/etc hält. Es wird sogar in ein ziemlich schickes Layout mit etwas Javascript und so, dass Sie sehen können, was drin ist und so. Vielleicht wollen Sie es überprüfen, wenn Sie nicht wussten, dass es existiert.

+0

Danke für diesen @Tropus. Die '$ request-> has ('username')' gibt jetzt 'true' zurück, aber die' $ request-> has ('email') 'gibt einen Fehler von:' Expectation failed für Methodenname ist gleich wenn Null oder mehrmals aufgerufen Parameter 0 für Aufruf Illuminate \ Http \ Request :: hat ('E-Mail') stimmt nicht mit dem erwarteten Wert überein. Fehler beim Bestätigen, dass zwei Strings gleich sind. Ich fügte ein weiteres Snippet für "E-Mail" hinzu, genauso wie das, was Sie angegeben haben, aber immer noch einen Fehler. – basagabi

+0

@basagabi Der erste Fall, in dem Sie sagen, dass Sie erwarten, dass eine bestimmte Methode führt, wird beim zweiten Mal, wenn Sie sie aufrufen, auf die erste definierte Zeit verschoben. In diesem Fall möchten Sie entweder einen Callback in der With-Anweisung oder ein at() anstelle der any() verwenden. Im Beispiel: 'erwartet ($ this-> at (0))' für das erste Auftreten und ' erwartet ($ this-> at (1)) 'für das zweite Vorkommen. Mehr Details in diesen ausgezeichneten Antworten [hier] (https://Stackoverflow.com/a/5989095) und [hier] (https://Stackoverflow.com/a/5484864/6649665) – Tropus

+0

Dies funktioniert perfekt! Du bist ein Lebensretter! – basagabi