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

使用sqlmock模拟gorm INSERT查询遇阻,寻求技术解决方案

解决sqlmock模拟gorm INSERT操作报错的问题

我之前在测试gorm的Create方法时也踩过这个一模一样的坑!SELECT测试跑起来完全正常,但一到INSERT就报错,看了gorm的调试日志才搞明白问题出在哪——gorm在执行INSERT时会自动加上RETURNING "groups"."id"子句(尤其是在PostgreSQL这类支持RETURNING语法的数据库中),而我们用sqlmock的时候很容易搞错监听的方法。

问题根源

gorm的Create方法在需要获取插入后的自增ID时,底层不是调用Exec,而是调用Query(因为要通过RETURNING返回结果)。如果我们用sqlmock.ExpectExec来监听这个操作,就会出现不匹配的报错,因为实际执行的是Query而非Exec。

解决方案

把ExpectExec换成ExpectQuery,并且匹配完整的SQL语句(包括后面的RETURNING部分),同时模拟返回包含ID的结果集。

举个具体的代码示例:

错误写法(会触发报错)

// 错误:用ExpectExec监听带RETURNING的INSERT
mock.ExpectExec(`INSERT INTO "groups"`).
    WithArgs("2018-05-01 17:46:15", "2018-05-01 17:46:15", nil, "Group 1", "A good group").
    WillReturnResult(sqlmock.NewResult(1, 1))

正确写法

// 正确:用ExpectQuery匹配完整的INSERT+RETURNING语句
mock.ExpectQuery(`INSERT INTO "groups" ("created_at","updated_at","deleted_at","name","description") VALUES ($1,$2,$3,$4,$5) RETURNING "groups"."id"`).
    WithArgs("2018-05-01 17:46:15", "2018-05-01 17:46:15", nil, "Group 1", "A good group").
    // 模拟返回插入后的自增ID
    WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))

额外注意点

  • 可以用正则模糊匹配SQL:比如^INSERT INTO "groups".*RETURNING "groups"."id",避免因为字段顺序或格式细节导致匹配失败
  • 参数类型要完全对应:时间字符串的格式、nil值的位置,都要和gorm实际传入的参数一致
  • 如果是MySQL数据库,gorm不会用RETURNING,而是依赖LastInsertId,这时候才需要用ExpectExec+WillReturnResult的写法

这样调整后,gorm的Create操作就能正常通过sqlmock的模拟测试了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:52:19