Laravel 5.6如何测试JSON/JSONb列?assertDatabaseHas失效处理
解决Laravel 5.6中测试完整JSON/JSONb列的问题
嘿,我之前在Laravel 5.6里也碰到过类似的困扰,这个版本对JSON列的断言支持确实不如后续版本灵活,不过有几个实用的办法能帮你一次性检查完整的JSON内容:
方法一:利用模型的类型转换(最简洁)
如果你的Eloquent模型已经给JSON列设置了类型转换,比如:
class YourModel extends Model { protected $casts = [ 'options' => 'array', // 自动把JSON列转为PHP数组 ]; }
那你完全可以直接通过模型实例来断言,不需要绕到数据库操作:
// 先执行你的store动作,比如创建模型 $model = $this->post('/your-store-route', $yourRequestData); // 定义预期的完整JSON数组(包含所有元数据) $expectedOptions = [ 'language' => 'en', 'theme' => 'dark', 'notifications' => ['email' => true, 'push' => false], // 其他所有需要检查的字段 ]; // 直接对比模型的属性即可 $this->assertEquals($expectedOptions, $model->options);
这种方式最直观,Laravel会自动帮你把数据库里的JSON字符串解码成数组,省去手动处理的麻烦。
方法二:手动查询数据库并解码对比
如果因为某些原因不能直接用模型实例(比如测试的是纯数据库操作),可以手动查询后解码对比:
// 执行store动作后,假设你知道目标记录的ID $targetRecordId = 1; $expectedOptions = [/* 你的完整JSON数组 */]; // 查询记录并解码JSON列 $record = DB::table('your_table')->find($targetRecordId); $actualOptions = json_decode($record->options, true); // 对比完整数组 $this->assertEquals($expectedOptions, $actualOptions);
如果JSON的键顺序可能不一致(比如前端传参顺序和数据库存储不同),可以用assertArraySubset忽略顺序只检查键值对(Laravel 5.6支持这个方法):
$this->assertArraySubset($expectedOptions, $actualOptions);
方法三:使用原生SQL条件断言存在
如果你坚持想用assertDatabaseHas,可以通过原生SQL的方式做JSON精确匹配,不同数据库语法略有区别:
针对MySQL:
$this->assertDatabaseHas('your_table', [ 'id' => $targetRecordId, DB::raw('options = ?') => json_encode($expectedOptions) ]);
针对PostgreSQL(JSONb类型):
$this->assertDatabaseHas('your_table', [ 'id' => $targetRecordId, DB::raw('options = ?::jsonb') => json_encode($expectedOptions) ]);
这种方式直接让数据库完成JSON的匹配校验,适合不需要解码到PHP数组的场景。
内容的提问来源于stack exchange,提问作者D.R.
相关产品推荐
相关产品推荐

