A clean approach to testing events and listeners

Focus on what each thing should do

Joel Clermont
Joel Clermont
2024-02-08

I really like Laravel feature tests. They're a great way to test a feature from the perspective of someone using your site, but without spinning up Dusk and a browser.

One area I see developers struggle with testing is events and listeners. How much of that code should be tested in the feature test?

Our approach is to only test that the event was dispatched in the feature test. We fake it out, assert it was dispatched the right number of times, and that the payload is expected, but the listener doesn't even run.

// tests/Feature/SomeFeatureTest.php
public function testSomeTestName(): void
{
    Event::fake([SomeEvent::class]);
    
    // the rest of your test setup

    // make the request that should fire the event
    
    // a bunch of other assertions related to this request

    Event::assertDispatchedTimes(SomeEvent::class, 1);
    Event::assertDispatched(SomeEvent::class, function (SomeEvent $event) {
        // inspect the event and make assertions about the payload
    });
}

Don't overlook testing the number of times your event was dispatched. You would definitely want to know if it was fired more times than you're expecting.

Then, we create a separate test for each listener. We categorize this as an integration test, because it's not making a request like a feature test, and we don't let our unit tests hit the database.

// tests/Integration/Listeners/SomeListenerTest.php
public function testSomeTestName(): void
{
    // set up the database with the data you need
    
    // don't fire the event, just call your listener directly
    $listener = new SomeListener();
    $listener->handle(new SomeEvent($somePayload);
    
    // make assertions here about what the listener should do
}

Now your feature test is focused on what the controller should do, but you can test the details of any listeners separately. It's much easier to understand and maintain.

Here to help,

Joel

P.S. Is your Laravel project lacking tests? Unsure where to even start? We can help!

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼

Level up your Laravel skills!

Each 2-minute email has real-world advice you can use.