如何在测试中模拟Laravel的JobQueued队列事件?
问题描述
我需要测试一个包中监听Laravel内置队列事件(Illuminate\Queue\Events命名空间下所有事件)的监听器。
平时测试事件监听器行为我会按以下步骤:
- 创建监听器要处理的事件
- 实例化监听器并调用
handle方法 - 断言操作是否正确执行
示例代码:
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); }
但针对JobQueued事件的监听器,我遇到了问题:
我的监听器代码:
public function handle(JobQueued $event): void { $jobUuid = $event->payload()['uuid']; if (property_exists($event->job, 'trackableJob')) { $this->updater->setQueuedStatus($event->job->trackableJob, $jobUuid); } }
尝试创建JobQueued事件时,不想手动构造复杂的payload参数:
public function test_updates_status_to_queued_in_database(): void { $event = new JobQueued(...); // 不想手动指定payload }
也试过直接调度任务并运行队列,但JobQueued事件从未触发:
public function test_updates_status_to_queued_in_database(): void { app(Dispatcher::class)->dispatch(new TrackedJob()); $this->artisan('queue:work --once'); }
补充:updater类的setQueuedStatus方法用于更新任务状态为已排队并关联UUID:
public function setQueuedStatus(TrackableJob $trackableJob, string $jobUuid): bool { $trackableJob->job_uuid = $jobUuid; return $trackableJob->update([ 'queued_at' => now(), 'status' => Status::Queued, ]); }
TrackedJob是一个handle方法为空的测试任务类。
请问如何正确创建JobQueued事件来测试我的监听器?
解决方案
方案一:模拟JobQueued事件(单元测试推荐)
不用手动构建完整的JobQueued实例,利用Mockery模拟监听器需要的属性和方法即可:
public function test_updates_status_to_queued_in_database(): void { // 1. 创建测试用的TrackableJob模型 $trackableJob = TrackableJob::factory()->create(); // 2. 模拟Job实例,添加trackableJob属性 $mockJob = Mockery::mock(\Illuminate\Contracts\Queue\Job::class); $mockJob->trackableJob = $trackableJob; // 3. 模拟JobQueued事件,返回包含uuid的payload $mockEvent = Mockery::mock(\Illuminate\Queue\Events\JobQueued::class); $mockEvent->job = $mockJob; $mockEvent->shouldReceive('payload') ->andReturn(['uuid' => 'test-uuid-123']); // 4. 获取监听器实例并调用handle方法 $listener = $this->app->make(YourJobQueuedListener::class); $listener->handle($mockEvent); // 5. 断言状态更新正确 $trackableJob->refresh(); $this->assertEquals('test-uuid-123', $trackableJob->job_uuid); $this->assertNotNull($trackableJob->queued_at); $this->assertEquals(Status::Queued, $trackableJob->status); }
方案二:让JobQueued事件真实触发(集成测试)
如果需要测试完整调度流程,调整队列配置并确保事件分发正常:
- 修改测试环境队列驱动:在
phpunit.xml中设置队列驱动为sync,任务会立即执行并触发队列事件:
<env name="QUEUE_CONNECTION" value="sync"/>
- 确保监听器已注册:如果包的服务提供者未自动注册监听器,可在测试中临时注册:
protected function setUp(): void { parent::setUp(); $this->app['events']->listen( \Illuminate\Queue\Events\JobQueued::class, YourJobQueuedListener::class ); }
- 编写测试代码:
public function test_updates_status_to_queued_in_database(): void { // 创建TrackableJob并关联到测试任务 $trackableJob = TrackableJob::factory()->create(); $job = new TrackedJob(); $job->trackableJob = $trackableJob; // 调度任务,sync驱动下会触发JobQueued事件 dispatch($job); // 断言状态更新正确 $trackableJob->refresh(); $this->assertNotNull($trackableJob->job_uuid); $this->assertNotNull($trackableJob->queued_at); $this->assertEquals(Status::Queued, $trackableJob->status); }
注意:sync驱动会让任务立即执行,同时按顺序触发JobQueued、JobProcessing等队列事件,适合测试完整流程。
内容的提问来源于stack exchange,提问作者user25728292
相关产品推荐
相关产品推荐

