You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel Job中Mock调用第三方的服务类?

问题出在哪?

你的Mock没生效,核心是两个原因:

  1. Job是异步执行的:默认情况下Laravel的Job会进入队列,在独立进程中运行,你在测试里绑定的Mock仅存在于当前测试进程的容器中,异步Job根本无法获取到这个Mock实例。
  2. 带参数的服务解析未匹配: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 20:50:29