【问题标题】:Laravel 5.2 Event Testing: expectsEvent not seeing the event fired although it is being firedLaravel 5.2 事件测试:expectsEvent 没有看到事件被触发,尽管它正在被触发
【发布时间】:2016-07-05 13:32:55
【问题描述】:

我一直在尝试测试事件,昨天我已经成功了。那是在我开始重构测试代码以防止它过于重复之前。我添加了 setUp 方法调用以使用 ModelFactories 生成假数据。这是昨天在每个测试用例中完成的,并且如上所述它正在工作。

我认为这与使用 setUp 方法有关,但我不知道为什么会这样。首先,我尝试使用 setUpBeforeClass() 静态方法,因为它只在单元测试运行时运行一次。然而,在第一次调用 setUp() 之前,laravel 应用程序实际上并没有设置......可能是一个可能的错误?它记录在此 SO 帖子 Setting up PHPUnit tests in Laravel

因此,我选择使用 setUp 方法,只检查静态属性是否为 null,如果为 null,则生成数据,如果不是,则继续执行。

这是在项目上运行 phpunit 的输出

➜  project git:(laravel-5.2-testing) ✗ phpunit
PHPUnit 5.2.10 by Sebastian Bergmann and contributors.

E                                                                  1 / 1 (100%)

Time: 8.94 seconds, Memory: 33.50Mb

There was 1 error:

1) UserEmailNotificationsTest::testNotificationSentOnGroupMediaSaving
Exception: These expected events were not fired: [\App\Events\GroupMediaSaving]

/Users/jcrawford/Dropbox/Work/Viddler/Repositories/l5_media_communities/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php:44
/Users/jcrawford/Dropbox/Work/Viddler/Repositories/l5_media_communities/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:127

FAILURES!
Tests: 1, Assertions: 0, Errors: 1, Skipped: 8.

这是我创建的单元测试文件的代码。

<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class UserEmailNotificationsTest extends \TestCase
{
    use DatabaseTransactions;

    const COMMUNITIES_TO_CREATE = 3;
    const USERS_TO_CREATE = 10;
    const ADMINS_TO_CREATE = 5;

    protected static $communities = null;
    protected static $users = null;
    protected static $admins = null;

    public function setUp()
    {
        parent::setUp(); // TODO: Change the autogenerated stub

        if(is_null(self::$communities)) {
            self::$communities = factory(\Community::class, self::COMMUNITIES_TO_CREATE)->create()->each(function ($community) {
                self::$users[$community->id] = factory(User::class, self::USERS_TO_CREATE)->create()->each(function (\User $user) use ($community) {
                    $user->community()->associate($community);
                    $user->save();
                });

                self::$admins[$community->id] = factory(User::class, self::ADMINS_TO_CREATE, 'superadmin')->create()->each(function (\User $admin) use ($community) {
                    $admin->community()->associate($community);
                    $admin->save();
                });

                $community->save();
            });
        }
    }

    public static function getRandomCommunityWithAssociatedData()
    {
        $community = self::$communities[mt_rand(0, count(self::$communities)-1)];
        return ['community' => $community, 'users' => self::$users[$community->id], 'admins' => self::$admins[$community->id]];
    }

    /**
     * Test that the notification event is fired when a group media
     * item is saved.
     */
    public function testNotificationSentOnGroupMediaSaving()
    {
        $data = self::getRandomCommunityWithAssociatedData();

        // FOR SOME REASON THIS SAYS THE EVENT IS NEVER FIRED WHEN IT ACTUALLY IS FIRED.
        $this->expectsEvents(['\App\Events\GroupMediaSaving']);

        $community = $data['community'];
        $admin = $data['admins'][0];
        $user = $data['users'][0];

        $asset = factory(Asset\Video::class)->make();
        $asset->community()->associate($community);
        $asset->user()->associate($admin);
        $asset->save();

        $group = factory(Group::class)->make();
        $group->community()->associate($community);
        $group->created_by = $admin->id;
        $group->save();


        $groupMedia = factory(GroupMedia::class)->make();
        $groupMedia->asset()->associate($asset);
        $groupMedia->user()->associate($user);
        $groupMedia->group()->associate($group);
        $groupMedia->published_date = date('Y-m-d H:i:s', strtotime('-1 day'));
        $groupMedia->save();

        // I can print_r($groupMedia) here and it does have an ID attribute so it was saved, I also put some debugging in the event object and it is actually fired.....
    }
}

关于为什么它没有看到被触发的事件有什么想法吗?如果我在测试用例中创建模型但在 setUp() 内完成时似乎失败了,我觉得奇怪的是它们被解雇了。最糟糕的是我没有在 setUp 方法中创建 GroupMedia 模型,而是在测试用例中完成。

我还转储了从 getRandomCommunityWithAssociatedData 方法返回的数据,它返回了正确的模型对象,它们都带有 id 属性,告诉我它们在创建过程中都保存到了数据库中。

这里要求的是实际触发事件的代码,它位于静态启动方法中的 GroupMedia 模型中。

protected static function boot()
{
    parent::boot();

    static::saving(function($groupMedia) {
        Event::fire(new \App\Events\GroupMediaSaving($groupMedia));
    });
}

【问题讨论】:

  • 我不确定静态属性(不是判断,我只是做不同的事情,example)。另外,根据laravel documentation,我认为您不应将数组作为参数传递,而应将 Event 本身传递:$this-&gt;expectsEvents('\App\Events\GroupMediaSaving');$this-&gt;expectsEvents(App\Events\GroupMediaSaving::class);
  • 好的,检查。您可以将数组作为参数传递。而且,您的事件类路径是否正确?在 PHP >= 5.5 你可以做$this-&gt;expectsEvents(App\Events\GroupMediaSaving::class);,如果路径无效,会通知你。
  • 不,我已经检查了路径,它们都适合我的事件并映射到实际的类。
  • 你在哪里触发App\Events\GroupMediaSaving的fire事件,你能把那个代码贴出来吗?
  • 我已将其添加到问题的末尾。

标签: laravel laravel-5.2


【解决方案1】:

如果您查看expectsEvents 的源代码(在特征Illuminate/Foundation/Testing/Concerns/MocksApplicationServices 内),您会看到它调用了函数withoutEvents,该函数模拟了应用程序事件调度程序,抑制并收集了所有future 事件。

你的问题是 setUp 函数此时已经被调用,所以你的事件不会被测试捕获和记录,也不会在评估断言时显示。

为了正确查看事件触发,您应该确保在触发事件的代码之前声明断言

【讨论】:

  • 是的,一千次。谢谢!
【解决方案2】:

同样的事情发生在我身上,$this-&gt;expectsEvent() 没有检测到事件被触发或阻止它传播到事件侦听器..

以前,我使用Event::fire(new Event()) 触发我的事件。我尝试将其更改为 event(new Event()) 并且测试现在突然可以正常工作了,它检测到事件已被触发并将事件静音。

【讨论】:

  • 同样的事情发生在我身上。使用 Event::fire() 导致测试失败,但使用 event() 通过
猜你喜欢
  • 1970-01-01
  • 2019-03-22
  • 2019-11-02
  • 2012-06-30
  • 1970-01-01
  • 2017-02-19
  • 2016-11-07
  • 2014-11-29
  • 1970-01-01
相关资源
最近更新 更多