2016-04-24 8 views
0

Spähen über das Internet, aber scheinen keine Antwort auf mein Problem zu finden. Ich habe in Laravel mit PHPUnit und Mothery in Test-Controller getaucht. Allerdings scheint ich meine eloquent-basierten Modelle nicht richtig zu verspotten. Ich habe es geschafft, meinen Auth :: user() auf die gleiche Weise zu verspotten, obwohl dies im folgenden Test nicht verwendet wird.Laravel 5 - Mit Mockery zu eloquenten Modell

Funktion in AddressController, die getestet werden soll:

public function edit($id) 
{ 
    $user = Auth::user(); 
    $company = Company::where('kvk', $user->kvk)->first(); 
    $address = Address::whereId($id)->first(); 

    if(is_null($address)) { 
     return abort(404); 
    } 

    return view('pages.address.update') 
     ->with(compact('address')); 
} 

ControllerTest Setup- und mock-Methode enthält

abstract class ControllerTest extends TestCase 
{ 
    /** 
    * @var \App\Http\Controllers\Controller 
    */ 
    protected $_controller; 

    public function setUp(){ 
     parent::setUp(); 
     $this->createApplication(); 
    } 

    public function tearDown() 
    { 
     parent::tearDown(); 
     Mockery::close(); 
    } 

    protected function mock($class) 
    { 
     $mock = Mockery::mock($class); 
     $this->app->instance($class, $mock); 
     return $mock; 
    } 
} 

AddressControllerTest verlauf ControllerTest

class AddressControllerTest extends ControllerTest 
{ 
    /** 
    * @var \App\Models\Address 
    */ 
    private $_address; 

    /** 
    * @var \App\Http\Controllers\AddressController 
    */ 
    protected $_controller; 

    public function setUp(){ 
     parent::setUp(); 
     $this->_controller = new AddressController(); 
     $this->_address = factory(Address::class)->make(); 
    } 

    public function testEdit404(){ 
     $companyMock = $this->mock(Company::class); 
     $companyMock 
      ->shouldReceive('where') 
      ->with('kvk', Mockery::any()) 
      ->once(); 
      ->andReturn(factory(Company::class)->make([ 
       'address_id' => $this->_address->id 
      ])); 

     $addressMock = $this->mock(Address::class); 
     $addressMock 
      ->shouldReceive('whereId') 
      ->with($this->_address->id) 
      ->once(); 
      ->andReturn(null); 

     //First try to go to route with non existing address 
     $this->action('GET', '[email protected]', ['id' => $this->_address->id]); 
     $this->assertResponseStatus(404); 
    } 
} 

Der Fehler es Werfen hält, ist:

1) AddressControllerTest::testEdit404 
Mockery\Exception\InvalidCountException: Method where("kvk", object(Mockery\Matcher\Any)) from Mockery_1_Genta_Models_Company should be called exactly 1 times but called 0 times. 

Vielleicht hat jemand eine Idee?

+0

Die Methode $ this-> call() wurde durch die Methode $ this-> action() ersetzt, während überprüft wurde, ob meine Controller-Methode überhaupt aufgerufen wurde und nach dem Ersetzen. Das Problem besteht jedoch weiterhin. –

Antwort

5

Okay, nachdem ich mehrere Beiträge von Jeffrey Way (dem Mann hinter Laracasts) gefunden habe, die Leuten empfehlen, keine eloquenten Objekte mehr zu verspotten und stattdessen in Speicherdatenbanken zu verwenden, habe ich diesen Ansatz ausprobiert. Ich dachte, das wäre vielleicht für andere Benutzer mit den gleichen Problemen in der Zukunft sehr brauchbar, so werde ich unten erklären.

Im Moment habe ich die Datei meiner ‚config/database.php‘ bearbeiten In-Memory-Datenbankoption mit SQLite zu unterstützen:

'sqlite' => [ 
      'driver' => 'sqlite', 
      'database' => ':memory:', 
      'prefix' => '', 
     ], 

Weiter oben auf die Datei, die Sie die folgende Konfiguration erhältlich :

'default' => env('DB_CONNECTION', 'mysql'), 

Dies kann gleich bleiben, bedeutet dies, dass Laravel Ihre .env Variablen überprüfen wird eine ‚dB_Connection‘ oder auch die Verwendung von mySQL als Standard zu finden. Dies ist wahrscheinlich das, was Sie tun möchten, wenn Sie Ihre Anwendung wie gewohnt ausführen. Beim Testen möchten Sie diese Konfiguration jedoch überschreiben und die Datenbankkonfiguration vorübergehend auf 'sqlite' setzen. Dies kann durch Zugabe des ‚DB_Connection‘ Variable auf Ihre .env Datei erfolgen:

DB_CONNECTION=mysql 

schließlich in Ihrer phpunit.xml, die Konfigurationsdatei von Laravel verwendet, um die Unit-Tests instantiatie, müssen Sie sagen, dass bei der Prüfung diese Variable soll auf ‚sQLite‘ gesetzt werden:

<env name="DB_CONNECTION" value="sqlite"/> 

Jetzt sind Sie fertig und Laravel wird ein unsichtbares in-Memory-Datenbank jeden Mal wenn Sie sind zu gehen Tests starten. Vergessen Sie nicht, den Tests, die die Datenbank benötigen, die folgende Zeile hinzuzufügen.

use \Illuminate\Foundation\Testing\DatabaseMigrations; 

Es wird sagen Laravel Ihre Datenbank Migrationen ausführen, bevor die Tests beginnen, so können Sie die Tabellen wie gewohnt verwenden.

So funktioniert es perfekt für mich! Hoffe ihr könnt es benutzen.

+0

Funktioniert gut für mich. Vielen Dank. Ich bin auch die DB nach der Migration säen.Nur ein Vorbehalt: Sie werden feststellen, dass '@depends testCreateCard'-Notation nicht funktioniert, sagen wir eine ID von Methode zu Methode, weil' setUp() 'einmal pro Test ausgeführt wird und die DB jedes Mal zurückgesetzt wird. Ich löste das Seeding meiner Daten und die Verwendung eines fest codierten Wertes. – mayid