2013-07-02 99 views
7

工作,我建立Laravel 4的模型端驗證與creating型號事件:Laravel 4模型事件不使用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; 
     }); 
    } 
} 

它運作良好,但我有一個PHPUnit的問題。以下兩個測試是完全一樣的,但探微第一個通:

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

如果我嘗試在同一個測試兩次創建一個用戶,它的工作原理,但它就像如果結合事件僅在存在我的測試班的第一次測試。在第一次測試執行期間,echo "Hello";僅打印一次。

我簡化了我的問題,但你可以看到問題:我不能在不同的單元測試中測試幾個驗證規則。幾小時後我幾乎嘗試了所有的事情,但我快要跳出窗戶了!任何想法 ?

+2

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

+2

謝謝。最後,模型事件不容易測試。我用這個技巧解決了我的問題:我在我的'setUp()'方法中調用'User :: boot()'。 –

+1

我更喜歡使用'User :: observe(new UserObserver)',這樣你就可以自己測試'UserObserver'。 – crynobone

回答

3

該問題在Github中有詳細記錄。見上面的評論,進一步解釋它。

我修改了Github中的'解決方案'之一,在測試過程中自動重置所有模型事件。將以下內容添加到TestCase.php文件中。

應用程序/測試/ 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

它以比我的基本技巧更爲通用的方式解決了我的問題(只需爲每個模型添加一行,如'User :: boot()'),但它讓我困惑,原因有兩個:它在我的代碼中添加了一些奇怪的代碼TestCase類,它在每次測試之前解析文件(這可能會導致性能問題)... –

+0

需要測試模型是否首先擴展Model,但有時它們可​​能沒有flushEventListeners方法。 – Benubird

0

我有我的子目錄中的模型,所以我編輯@TheShiftExchange碼有點

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