如何在Laravel Job中Mock调用第三方的服务类?
问题出在哪?
你的Mock没生效,核心是两个原因:
- Job是异步执行的:默认情况下Laravel的Job会进入队列,在独立进程中运行,你在测试里绑定的Mock仅存在于当前测试进程的容器中,异步Job根本无法获取到这个Mock实例。
- 带参数的服务解析未匹配:Job里用
resolve(ManagementService::class, ['manager_id' => ...])带参数获取服务,但你测试中的Mock没有针对这种带参数的解析请求做绑定,容器依然会创建真实的ManagementService实例。
怎么解决?
1. 让Job在测试中同步执行
在测试方法开头添加以下代码,强制队列使用同步驱动,确保Job在当前测试进程内执行:
$this->app['config']->set('queue.default', 'sync');
如果嫌重复,也可以在测试类的setUp()方法里全局设置,不用每个测试都写。
2. 针对带参数的解析绑定Mock
Laravel默认的mock()方法只匹配无参数的服务解析,你需要手动绑定带参数的场景:
// 创建Mock实例 $mock = Mockery::mock(ManagementService::class); $mock->shouldReceive('callApi') ->with('/thirdparty/call') // 可选:指定接口路径,确保匹配正确的调用 ->andReturn('none'); // 绑定到容器,匹配带manager_id的解析请求 $this->app->bind(ManagementService::class, function ($app, $parameters) use ($mock) { // 这里根据你测试传入的manager_id做匹配,比如示例中的4 if (isset($parameters['manager_id']) && $parameters['manager_id'] == 4) { return $mock; } // 其他情况可以返回真实实例,或根据需求处理 return $app->makeWith(ManagementService::class, $parameters); });
3. 替代方案:捕获Job手动执行
不想修改队列驱动的话,用Queue::fake()捕获Job,然后手动执行它的handle()方法,这样Job会在当前测试进程内运行,Mock就能生效:
Queue::fake(); // 发送请求触发Job分发 $response = $this->actingAs(User::factory()->create())->post('/myroute', [ 'manager_id' => 4, ]); // 捕获Job并手动执行 Queue::assertPushed(MyJob::class, function ($job) { $job->handle(); return true; });
这种方式还能顺便断言Job是否被正确推送,一举两得。
完整测试代码示例
public function test_store_route_mocks_third_party_call() { // 开启同步队列 $this->app['config']->set('queue.default', 'sync'); // 创建Mock并绑定带参数的解析 $mock = Mockery::mock(ManagementService::class); $mock->shouldReceive('callApi') ->with('/thirdparty/call') ->andReturn('none'); $this->app->bind(ManagementService::class, function ($app, $parameters) use ($mock) { if ($parameters['manager_id'] == 4) { return $mock; } return $app->makeWith(ManagementService::class, $parameters); }); // 发送请求 $response = $this->actingAs(User::factory()->create())->post('/myroute', [ 'manager_id' => 4, ]); // 断言响应状态 $response->assertStatus(200); // 验证Mock方法确实被调用 $mock->shouldHaveReceived('callApi')->once(); }
内容的提问来源于stack exchange,提问作者Nathan Meyer
相关产品推荐
相关产品推荐

