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

如何使用Mockery正确mock Laravel模型的save()方法 避免触发数据库请求

Mock save方法未生效问题解决方案

根本原因

你当前写法的核心问题是:JobAccessor::find()返回的是你手动new出来的真实Job模型实例,和你在setup函数中创建并绑定到容器的$this->job mock对象不是同一个实例。你给$this->job设置的save方法调用预期,不会作用到真实实例上,因此$job->save()调用时依然会执行原生数据库逻辑,抛出数据库驱动异常。

另外注意:你在容器中绑定的App\Models\Job mock,仅对通过容器make()方式创建的Job实例生效,手动new出来的Job实例不受容器绑定约束。

解决方法

方案1:让find方法返回带save预期的mock实例

直接构造mock的Job对象,绑定save调用预期后,作为find方法的返回值即可:

// 测试函数修改后代码
// 构造partial mock,保留模型原有属性/方法逻辑,仅mock需要屏蔽的save方法
$mockJob = Mockery::mock(Job::class)->makePartial();
$mockJob->id = 22;
$mockJob->user_id = 123;
// 绑定save方法的调用预期
$mockJob->shouldReceive('save')->once()->andReturnTrue();

$this->jobAccessor->shouldReceive('find')
   ->with($jobId)
   ->andReturns($mockJob);

方案2:对已有的真实Job实例做部分mock

如果你需要保留new Job()初始化的属性逻辑,可以对已创建的真实实例做部分mock,只重写save方法:

// 测试函数修改后代码
$job = new Job([
    'id' => 22,
    'user_id' => 123
]);
// 对现有实例做partial mock,仅覆盖save方法
$mockJob = Mockery::mock($job)->makePartial();
$mockJob->shouldReceive('save')->once()->andReturnTrue();

$this->jobAccessor->shouldReceive('find')
   ->with($jobId)
   ->andReturns($mockJob);

注意事项

  • 可以根据测试场景调整save方法的返回值,比如andReturnFalse()模拟保存失败的分支逻辑
  • 如果不需要保留模型原生逻辑,可去掉makePartial(),创建纯mock对象

内容的提问来源于stack exchange,提问作者Luke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 15:45:03