Laravel 5.1 测试环境中的 Eloquent 模型事件

3

我有一个 Eloquent 模型,其中在模型的 boot() 方法中定义了一些观察者方法。这是非常简单的逻辑 - 我使用 creating() 静态方法来为属性定义默认值,如果在调用 Model::create([...]) 时未定义该属性。

protected static function boot()
{
    parent::boot();
    static::creating(function (Content $content) {
        static::setDefaultValues($content);
    });
}

protected static function setDefaultValues(Content $content)
{
    if ( ! $content->published_at) {
        $content->published_at = Carbon::now();
    }
}

通过浏览器或使用artisan tinker控制台或数据库seeder,应用程序可以正常工作。

但是,当我尝试使用相同的数据库填充逻辑通过artisan命令引导测试数据库时,在运行测试用例时会抛出异常,称特定属性不能为空。经过一些研究和挖掘Laravel代码,我发现事件分派器应该正常工作,因为我没有模拟任何事件也没有使用withoutEvents()助手。

此外,全局作用域在测试环境中似乎不适用。

我在几个关键点上放置了var_dumps(在调用creating()后立即,在Eloquent\Model类中的save()方法内部以及在模型事件触发后),以检查属性并注意到观察者方法正在执行,但效果就像模型实例没有通过引用传递给事件处理程序,而是被克隆了。相同的代码在开发环境中可以正常运行,但在测试环境中会失败。

有人遇到过这样的问题吗?我真的不知道该怎么办,请给予任何建议。

值得一提的是,我在开发中使用MySQL,并尝试在SQLite数据库中运行测试以便于使用。测试是使用Laravel的开箱即用的PHPUnit测试设置运行的。

1个回答

1

将所有模型事件绑定的声明移动到AppServiceProvider::boot()方法中,如下所示

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        \App\Content::creating(function (Content $content) {
            $content::setDefaultValues($content); // change to public
        });

        // other bindings
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

跟随http://laravel.com/docs/5.1/eloquent#events

你也可以使用该方法来附加模型观察者。


能否更加通用化?例如使用 Model 类? - carlituxman
我尝试使用一个BaseModel类并调用BaseModel :: creating但不起作用。 - carlituxman
我不这么认为,因为事件分发器使用模型类名称来格式化事件名称。请看Model::fireModelEvent($event)。因此,“eloquent.creating User”与“eloquent.creating BaseModel”不匹配。 - absolux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接