如何防止模型事件使用 phpunit 触发?
Posted
技术标签:
【中文标题】如何防止模型事件使用 phpunit 触发?【英文标题】:How to prevent Model events from firing using phpunit? 【发布时间】:2015-12-24 06:03:43 【问题描述】:我想阻止诸如“已创建”之类的模型事件。使用 phpunit 测试我的应用程序时“更新”等。
在 Laravel 的文档中,它说您可以使用
来阻止事件触发$this->expectsEvents(App\Events\UserRegistered::class);
但在我的情况下,我没有课可期待。
即使我使用$this->withoutEvents();
来阻止所有事件,也会触发 eloquent 事件。
我怎样才能防止雄辩的事件发生?
【问题讨论】:
您是否尝试过使用 Mockery 包创建模拟?我认为这应该会有所帮助。 不,我没有。你能说得更具体点吗? 这是一个嘲弄的 repo,你应该看看它和文档github.com/padraic/mockery 这并不能解决我的问题。 【参考方案1】:查看 Laravel Api Model::flushEventListeners()
应该“删除模型的所有事件侦听器”。
编辑
您可以在此基础上编写自定义方法:
public static function flushEventListeners()
if (! isset(static::$dispatcher))
return;
$instance = new static;
foreach ($instance->getObservableEvents() as $event)
static::$dispatcher->forget("eloquent.$event: ".get_called_class());
可能是这样的:
public static function flushEventListenersProvided($events)
if (! isset(static::$dispatcher))
return;
$instance = new static;
foreach ($instance->getObservableEvents() as $event)
if(in_array($event, $events))
static::$dispatcher->forget("eloquent.$event: ".get_called_class());
并且可能将其作为特征添加到模型中,或者作为所有模型都将扩展的基本模型。此代码未经测试,但应该让您了解如何完成它。
【讨论】:
这非常有用,但在我的情况下,我只想阻止一些模型事件。例如“保存”或“创建”等。 这似乎工作正常,但我不想将此功能添加到我需要测试的所有模型中。它必须是一种直接从我的测试文件中执行的方法。 我在文档中找不到任何其他内容。我建议创建一个特征并将其包含在模型中,或者为所有模型创建一个基本模型,将其放在那里并从中扩展所有模型。【参考方案2】:如果你真的只是想禁用模型的观察者,例如creating
、created
、updated
等,那么你可以调用模型的外观方法unsetEventDispatcher
。
例如,您可以将其放在测试类的setUp
方法中。而且您不必在tearDown
中重置它,因为框架会自动在setUp
中为下一次测试执行此操作。
protected function setUp(): void
parent::setUp();
App\MyModel::unsetEventDispatcher();
如果您希望这是临时的,请查看withoutEventDispatcher
。
您也可以getEventDispatcher
并将其保存到一个临时变量,然后在您完成业务后再次setEventDispatcher
,如此答案所示:https://***.com/a/51301753/4233593
【讨论】:
【参考方案3】:方法一:
您可以通过模拟观察者来阻止模型事件触发。方法如下:
public function my_sexy_test()
$this->app->bind(MyModelObserver::class, function ()
return $this->getMockBuilder(MyModelObserver::class)->disableOriginalConstructor()->getMock();
);
factory(MyModel::class)->states('pending')->create([
'user_id' => 1,
'publisher_revenue' => 10,
]);
// Your test logic goes here
方法二:
您可以在 setUp() 方法中调用以下内容:
MyModel::unsetEventDispatcher();
在 Laravel 5.6 中测试和工作。
【讨论】:
【参考方案4】:查看Model
类的shouldReceive
方法。基本上Model
类扩展了Mockery
。
这是一个假设你有一个类Car
的例子:
Car::shouldReceive('save')->once();
这不会命中数据库,而是使用模拟。你可以在这里找到更多关于 Laravel 测试的信息:http://laravel.com/docs/4.2/testing
希望这会有所帮助。
【讨论】:
这并不能回答您最初的问题,而是更多的选择【参考方案5】:你应该可以使用
$model = new App\Model($inputs);
$this->expectsEvents(['eloquent.creating: App\Model', 'eloquent.saved: App\Model']);
$model->save();
【讨论】:
试过这个解决方案了吗?它返回一个异常EventTest::testExample Exception: The following events were not fired: [eloquent.creating: App\Model]
我也尝试过不同的事件。
我已经使用 Log 来跟踪所有触发的事件,而 'eloquent.creating: App\Model' 是触发的事件之一。我不明白为什么嘲弄不能抓住它。
经过大量测试后,我发现这永远不会奏效,即使嘲弄不会触发错误。
有谁知道为什么这不起作用?我会说应该,但这里有什么替代方案?以上是关于如何防止模型事件使用 phpunit 触发?的主要内容,如果未能解决你的问题,请参考以下文章