2013-07-02 11 views
7

zbudować walidację modelu boku w laravel 4 z creating modelu zdarzeń:laravel 4 model wydarzenia nie działają z PHPUnit

class User extends Eloquent { 

    public function isValid() 
    { 
     return Validator::make($this->toArray(), array('name' => 'required'))->passes(); 
    } 

    public static function boot() 
    { 
     parent::boot(); 

     static::creating(function($user) 
     { 
      echo "Hello"; 
      if (!$user->isValid()) return false; 
     }); 
    } 
} 

To działa dobrze, ale mam problemy z PHPUnit. Dwa kolejne testy są dokładnie takie same, ale juste pierwszy pass:

class UserTest extends TestCase { 

    public function testSaveUserWithoutName() 
    { 
     $count = User::all()->count(); 

     $user = new User; 
     $saving = $user->save(); 

     assertFalse($saving);      // pass 
     assertEquals($count, User::all()->count()); // pass 
    } 

    public function testSaveUserWithoutNameBis() 
    { 
     $count = User::all()->count(); 

     $user = new User; 
     $saving = $user->save(); 

     assertFalse($saving);      // fail 
     assertEquals($count, User::all()->count()); // fail, the user is created 
    } 
} 

Gdy próbuję utworzyć użytkownika dwa razy w tym samym teście, to działa, ale to jest jak gdyby zdarzenie wiązania występuje tylko w pierwszy test mojej klasy testowej. echo "Hello"; jest drukowany tylko jeden raz, podczas pierwszego wykonania testu.

Uproszczę sprawę dla mojego pytania, ale widać problem: nie mogę przetestować kilku reguł sprawdzania poprawności w różnych testach jednostkowych. Próbuję prawie wszystkiego od godzin, ale jestem już blisko, aby wyskoczyć przez okna! Dowolny pomysł ?

+2

Czytaj https://github.com/laravel/framework/issues/1181 – crynobone

+2

Dziękuję. Wreszcie zdarzenia modelowe nie są łatwe do sprawdzenia. Rozwiązuję swój problem z tą sztuczką: W mojej metodzie 'setUp()' nazywam 'User :: boot()'. –

+1

Wolę używać 'User :: observe (new UserObserver)', w ten sposób możesz przetestować 'UserObserver' na swoim komputerze. – crynobone

Odpowiedz

3

Kwestia jest dobrze udokumentowana w Github. Zobacz powyższe komentarze, które wyjaśniają to dalej.

Zmodyfikowałem jedno z "rozwiązań" w Github, aby automatycznie resetować wszystkie zdarzenia modelu podczas testów. Dodaj następujące elementy do pliku TestCase.php.

app/testy/TestCase.php

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


private function resetEvents() 
{ 
    // Get all models in the Model directory 
    $pathToModels = '/app/models'; // <- Change this to your model directory 
    $files = File::files($pathToModels); 

    // Remove the directory name and the .php from the filename 
    $files = str_replace($pathToModels.'/', '', $files); 
    $files = str_replace('.php', '', $files); 

    // Remove "BaseModel" as we dont want to boot that moodel 
    if(($key = array_search('BaseModel', $files)) !== false) { 
     unset($files[$key]); 
    } 

    // Reset each model event listeners. 
    foreach ($files as $model) { 

     // Flush any existing listeners. 
     call_user_func(array($model, 'flushEventListeners')); 

     // Reregister them. 
     call_user_func(array($model, 'boot')); 
    } 
} 
+0

Rozwiązuje to mój problem w bardziej ogólny sposób niż moja podstawowa sztuczka (po prostu dodaj jedną linię, jak "User :: boot()" dla każdego modelu), ale pozwala mi to z dwóch powodów: dodaje kilka dziwnych kodów w moim Klasa TestCase i parsuje pliki przed każdym testem (co może spowodować problemy z wydajnością) ... –

+0

Wymaga sprawdzenia, czy model najpierw rozszerza Model, czasami może nie mieć metody flushEventListeners. – Benubird

0

mam moje modele w podkatalogów więc edytowany kod @TheShiftExchange nieco

//Get all models in the Model directory 
$pathToModels = '/path/to/app/models'; 
$files = File::allFiles($pathToModels); 

foreach ($files as $file) { 
    $fileName = $file->getFileName(); 
    if (!ends_with($fileName, 'Search.php') && !starts_with($fileName, 'Base')) { 
     $model = str_replace('.php', '', $fileName); 
     // Flush any existing listeners. 
     call_user_func(array($model, 'flushEventListeners')); 
     // Re-register them. 
     call_user_func(array($model, 'boot')); 
    } 
}