mvE's avatar
Level 1

Test event listeners that listen to queue events

I have a bunch of event listeners that listen to Laravel's queue events in order to track and update the status of a job. I am listening for the JobQueued, JobProcessing, JobProcessed, JobFailed, JobTimedOut events. An example of one of these listeners is the listener that listens to the JobProcessing event:

public function handle(JobProcessing $event): void
{
    $jobUuid = $event->job->uuid();

    if ($this->updater->trackableJobModelExists($jobUuid)) {
        $trackableJobModel = $this->updater->retrieveTrackableJobModel($jobUuid);

        $this->updater->setProcessingStatus($trackableJobModel);
    }
}

I can test whether my listener listens to this event by doing this:

public function test_listens_to_laravel_job_processing_event(): void
{
    Event::fake();

    Event::assertListening(
        JobProcessing::class, 
        SetTrackableJobProcessingStatus::class
    );
}

I would like to test whether the event listener works and updates the record in the database. I tried:

public function test_updates_status_to_processing(): void
{
    $eventListener = new SetTrackableJobProcessingStatus(new TrackableJobUpdater());
    $eventListener->handle(new JobProcessing('default', new TrackedJob()));

    // ... assertions
}

But I get the error/warning:

Expected parameter of type '\Illuminate\Contracts\Queue\Job', '\App\Tests\Jobs\TrackedJob' provided

What would be the proper way to test something like this?

0 likes
2 replies
martinbean's avatar

@mve Manually call your listener’s handler method, giving it an event instance with the data you want, and assert that the listener performed the side effects you were expecting:

public function testUpdatedStatusToProcessing(): void
{
    $event = new JobProcessing(...);

    $listener = $this->app->make(YourListener::class);
    $listener->handle($event);

    // Assertions...
}
mvE's avatar
Level 1

Thanks for the answer. The issue is more about properly creating the JobProcessing event instance:

Many queue events like JobProcessing, JobProcessed etc expect a \Illuminate\Contracts\Queue\Job instance for the job parameter. Passing an actual job like: new TrackedJob() won't work. I was hoping something like this would work:

public function test_updates_status_to_processing(): void
{
    Queue::push(new TrackedJob());

    $event = new JobProcessing(
        'default',
        Queue::pop(),
    );

    $listener = $this->app->make(SetTrackableJobProcessingStatus::class);
    $listener->handle($event);

     // assertions
 }

But that gives the error: Call to a member function uuid() on null indicating that Queue::pop did not return a job.

Please or to participate in this conversation.