如何使用phpunit防止模型事件被触发?

时间:2015-09-26 15:03:14

标签: laravel testing laravel-4 laravel-5 phpunit

我想阻止模拟事件,例如' created'。 '更新'等,使用phpunit测试我的应用程序。

在Laravel的文档中,它说您可以使用

防止事件被触发

$this->expectsEvents(App\Events\UserRegistered::class);

但在我的情况下,我没有期望的课程。

即使我使用$this->withoutEvents();来阻止所有事件,也会触发雄辩的事件。

如何防止有说服力的事件?

5 个答案:

答案 0 :(得分:9)

调查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());
        }
    }
}

并且可能将其添加为模型的特征,或者所有模型将扩展的基本模型。此代码未经测试,但应该让您了解如何完成。

答案 1 :(得分:1)

查看shouldReceive课程的Model方法。基本上Model类扩展Mockery。 这是一个假设你有一个班级Car的例子:

Car::shouldReceive('save')->once();

这不会命中数据库,而是会使用mock。您可以在此处找到有关Laravel测试的更多信息:http://laravel.com/docs/4.2/testing

希望这有帮助。

答案 2 :(得分:1)

你应该可以使用

$model = new App\Model($inputs);

$this->expectsEvents(['eloquent.creating: App\Model', 'eloquent.saved: App\Model']);

$model->save();

答案 3 :(得分:1)

如果您真的只想禁用模型的观察者,例如creatingcreatedupdated等,则可以调用模型的外观方法unsetEventDispatcher

例如,您可以将其放在测试类的setUp方法中。而且您不必在tearDown中将其重置,因为框架会在setUp中为下一次测试自动执行此操作。

protected function setUp(): void
{
    parent::setUp();
    App\MyModel::unsetEventDispatcher();
}

如果您希望这是临时的,请查看withoutEventDispatcher

此外,您可以getEventDispatcher并将其保存到临时变量中,然后在完成业务后再次setEventDispatcher,如以下答案所示:https://stackoverflow.com/a/51301753/4233593

答案 4 :(得分:0)

方法1:

您可以通过模拟Observer来阻止模型事件触发。以下是:

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
}

方法2:

您可以在setUp()方法中调用以下内容:

 MyModel::unsetEventDispatcher();

在Laravel 5.6中进行了测试和工作。