Question

How to mock/simulate Laravel JobQueued queue event in test?

I want to test multiple event listeners that listen for Laravel's built-in queue events (all the events that live in the Illuminate\Queue\Events namespace. The listeners are part of a package.

Normally, if I want to test the behaviour of an event listener, I would do something like this:

  1. Create the event that the listener should handle.
  2. Instantiate the event listener and call its handle method on the event.
  3. Assert that the actions (in this example sending a notification) are executed properly.
public function test_sends_notification_to_newly_created_user(): void
{
    $user = User::factory()->create();
    $event = new UserCreated($user);

    $eventListener = $this->app->make(SendUserCreationNotification::class);
    $eventListener->handle($event);

    Notification::assertSentTo($user, WelcomeNotification::class);
}

My listener that listens to the JobQueued event:

public function handle(JobQueued $event): void
{
    $jobUuid = $event->payload()['uuid'];

    if (property_exists($event->job, 'trackableJob')) {
        $this->updater->setQueuedStatus($event->job->trackableJob, $jobUuid);
    }
}

When I try to create the JobQueued event:

public function test_updates_status_to_queued_in_database(): void
{
    $event = new JobQueued(...); // I have to manually specify the payload (don't want to do that)
}

I also tried just dispatching a job and running it but the JobQueued event never fires:

public function test_updates_status_to_queued_in_database(): void
{
    app(Dispatcher::class)->dispatch(new TrackedJob());
    
    $this->artisan('queue:work --once');
}

How do I properly create the JobQueued event, so I can test my listener?

For clarification, the setQueuedStatus() method on the updater class. Its purpose is to set the status to queued and attach the uuid, which we can then use to track it during processing.

public function setQueuedStatus(TrackableJob $trackableJob, string $jobUuid): bool
{
    $trackableJob->job_uuid = $jobUuid;

    return $trackableJob->update([
        'queued_at' => now(),
        'status' => Status::Queued,
    ]);
}

The TrackedJob class is a test job with an empty handle() method.

 3  225  3
1 Jan 1970

Solution

 1

This (the Illuminate\Queue\Events\JobProcessing event) counts as laravel internals. You should not be wasting your time trying to test it.

What you can test however is

  1. Your event is dispatched when you visit an endpoint / submit a form & whatever.
  2. Your event is dispatched on the queue you expect it to be dispatched.
  3. Your event has your listener attached to it.
  4. Your listener does what you think it will do.
2024-06-27
IGP