Laravel 4 Model Events don't work with PHPUnit

核能气质少年 提交于 2020-01-13 08:58:08

问题


I build a model side validation in Laravel 4 with the creating Model Event :

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

It works well but I have issues with PHPUnit. The two following tests are exactly the same but juste the first one 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
    }
}

If I try to create a user twice in the same test, it works, but it's like if the binding event is present only in the first test of my test class. The echo "Hello"; is printed only one time, during the first test execution.

I simplify the case for my question but you can see the problem : I can't test several validation rules in different unit tests. I try almost everything since hours but I'm near to jump out the windows now ! Any idea ?


回答1:


The issue is well documented in Github. See comments above that explains it further.

I've modified one of the 'solutions' in Github to automatically reset all model events during the tests. Add the following to your TestCase.php file.

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



回答2:


I have my models in subdirectories so I edited @TheShiftExchange code a bit

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


来源:https://stackoverflow.com/questions/17428050/laravel-4-model-events-dont-work-with-phpunit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!