是否有 Laravel 的测试方法来检测事件触发的次数?

4

我正在使用基础的PHPUnit配置文件和默认的TestCase.php文件。

我正在寻找一种方法来检查在测试过程中是否多次触发了某个事件。当前的代码如下:

function test_fires_multiple_events()
{
    $this->expectsEvents(SomeEvent::class);
}

理想情况下,我希望有以下内容:
function test_fires_multiple_events()
{
    $this->expectsEvents(SomeEvent::class)->times(3);
}
4个回答

4

在查看了MocksApplicationServices的代码之后,我成功地利用trait并在withoutEvents()方法中捕获到它所包含的字段。

相应的扩展代码如下:

function test_fires_multiple_events()
{
    $this->withoutEvents(); // From MocksApplicationServices

    $c = collect($this->firedEvents)
                ->groupBy(function($item, $key) { return get_class($item); })
                ->map(function($item, $key) { return $item->count(); });

    $this->assertsEqual(3, $c->get(SomeEvent::class));

}

为了解释collection做了什么:

1) collect($this->firedEvents): 获取捕获的事件并将其存储在一个集合中。重要的是要注意,MocksApplicationServices将每个事件推送到一个数组中,这意味着它已经在计算。

2) groupBy(function($item, $key) { return get_class($item); }): 按类名分组,因此现在我们有一组数组。

3) map(function($item, $key) { .. }: 简单地累加子项。

这将产生像下面这样的结构:

Illuminate\Support\Collection (1) (
    protected items -> array (2) [
        'App\Events\SomeEvent' => integer 2
        'App\Events\SomeOtherEvent' => integer 1
    ]
)

编辑 为了让代码更加清晰 - 你可以将以下代码添加到你的基础测试用例文件中:

public function assertEventFiredTimes($event, $count)
{
    $this->assertEquals(
        count(collect($this->firedEvents)
            ->groupBy(function($item, $key) { return get_class($item); })
            ->get($event, [])),
        $count
    );
}

然后在你的测试中:


$this->assertEventFiredTimes(SomeEvent::class, 3);

不要忘记添加withoutEvents()

优秀的方法和优雅的解决方案,只有一件事:有时firedEvents数组可能包含字符串和对象事件(例如“kernel.handled”或“locale.changed”)。因此,您可能需要在groupBy函数中使用{ return is_string($item) ? $item : get_class($item); },以便它可以处理任何类型的事件。 - kerwan

2

1
我感谢您提供的链接 - 我正在阅读它。但是stackoverflow通常更喜欢答案包括大部分解决方案(如果需要,可以附带参考链接)。这是为了避免未来的死链接。再次感谢。 - Chris

2

1
我认为您需要将事件分派器注入到您的类中,然后模拟它,这样您就可以做出以下操作:
$dispatcher->shouldReceive('fire')->with(SomeEvent::class)->times(3);

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