KiaiFighter
KiaiFighter

Reputation: 667

Laravel Event Fires but PHPUnit doesn't detect that it fired

I am running a test to ensure my events are firing properly.

MyTest

/** @test */
public function foil_products_DO_trigger_oos_event ()
{
    $this->setUpTheWorld(true, 1);
    $response = $this->sendInStockData($this->pusher, Carbon::now()->subHour());

    $this->expectsEvents(\App\Events\InventoryOutOfStock::class);
    $this->sendCustomStockData($this->pusher, 0, 1, Carbon::now());

    // TEST THE RESULTS OF THE LISTENER FOR THAT EVENT
    $this->pusher = $this->pusher->fresh();
    $this->assertEquals(1, $this->pusher->oos);

    $this->assertCount(2, $this->pusher->inventories, "Pusher doesnt have 2 Inventories");
    $this->assertEquals(0, $this->pusher->latestInventory->tags_blocked);
}

If I comment out the line:

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

Then my test will pass. The line:

    $this->assertEquals(1, $this->pusher->oos);

passes and this would only happen if the event fired. Additionally, I looked at my log file and I can guarantee that the event fired....

Is there anything I am doing wrong to tell PHPUnit that these events will be firing???

Thank you!

EventServiceProvider

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        \App\Events\InventoryOutOfStock::class => [
            \App\Listeners\InventoryOutOfStockUpdater::class,
            \App\Listeners\EmailInventoryOutOfStockNotification::class,
            \App\Listeners\SMSInventoryOutOfStockNotification::class,
        ],
    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);
    }
}

Upvotes: 6

Views: 5145

Answers (3)

Abraham Brookes
Abraham Brookes

Reputation: 2007

In order to use the $listen array in a service provider, your service provider class needs to extend Illuminate\Foundation\Support\Providers\EventServiceProvider as opposed to your usual Illuminate\Support\ServiceProvider - if you used php artisan create:provider then that will extend ServiceProvider so you need to change the extends line.

In my case it made more sense to break my package event provider out from my normal package provider because I didn't want to drag all the eventy stuff in to my normal package provider. Packages can have multiple providers you just need to register each one in your config/app.php <3

Upvotes: 0

D0mski
D0mski

Reputation: 91

Kind of an old question but I think previous answer doesn't really capture the issue.

The problem here is that you expect your event to fire and the listener to do something, while THIS WILL NOT HAPPEN here. Calling expectsEvent() asserts that the event fired but prevents listeners from firing, as official documentation states:

Laravel provides a convenient expectsEvents method that verifies the expected events are fired, but prevents any handlers for those events from running.

Read more: https://laravel.com/docs/5.2/testing#mocking-events

Try to simplify and separate your tests. Test either only that an event is fired, or that the listener does the what's expected, depending on complexity and separation of concerns.

Upvotes: 7

Kenyon
Kenyon

Reputation: 817

I realize this is a pretty old question, but I just had this problem and I figured I would post the solution.

$this->expectsEvents($events)

doesn't work like an assertion. It doesn't assert anything until the very end. What is does is once it reaches that line, it expects that event to happen AFTER you've said you expected it.

TL;DR put the expectsEvents line at the top of your test method.

Here is a link to vague docs that don't really explain this, but they do say it. Kind of. https://laravel.com/docs/5.2/testing#mocking-events

Upvotes: 5

Related Questions