2013-07-02 69 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')); 
    } 
}