2013-07-02 16 views
7

Costruisco una validazione lato modello laravel 4 con l'evento creating Modello:laravel 4 Modello Eventi non funzionano con 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; 
     }); 
    } 
} 

Funziona bene ma non ho problemi con PHPUnit. I due seguenti prove sono esattamente gli stessi ma juste il primo passaggio:

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

Se provo a creare un utente due volte nello stesso test, funziona, ma è come se l'evento di legame è presente solo nel primo test della mia classe di test. echo "Hello"; viene stampato una sola volta, durante la prima esecuzione del test.

Semplifico il caso per la mia domanda ma è possibile vedere il problema: non riesco a testare più regole di convalida in diversi test di unità. Provo quasi tutto da ore, ma ora sono vicino a saltare fuori dalle finestre! Qualche idea ?

+2

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

+2

Grazie. Infine, gli eventi modello non sono facilmente testabili. Risolvo il mio problema con quel trucco: chiamo 'User :: boot()' nel mio metodo 'setUp()'. –

+1

Preferisco usare 'User :: observ (new UserObserver)', in questo modo puoi testare 'UserObserver' da solo. – crynobone

risposta

3

Il problema è ben documentato in Github. Vedi i commenti sopra che lo spiegano ulteriormente.

Ho modificato una delle "soluzioni" in Github per ripristinare automaticamente tutti gli eventi del modello durante i test. Aggiungi il seguente al tuo file TestCase.php.

app/test/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

Risolve il mio problema in un modo più generico del mio trucco base (basta aggiungere una riga come 'User :: boot()' per ogni modello) ma mi lascia perplesso per due motivi: aggiunge un po 'di codice strano nel mio Classe TestCase e analizza i file prima di ogni test (che potrebbero causare problemi di prestazioni) ... –

+0

È necessario verificare se il modello estende prima il Modello, a volte potrebbe non avere il metodo flushEventListeners. – Benubird

0

ho i miei modelli in sottodirectory così ho modificato il codice @TheShiftExchange un po

//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')); 
    } 
} 
Problemi correlati