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

使用go-sqlmock模拟查询时的结果异常与条件校验问题

解决go-sqlmock模拟查询的两个问题

问题1:预期返回最大tid值3,实际返回1

你的测试代码里,虽然给mock结果集添加了1和3两行,但QueryRow只会读取结果集的第一行。而原查询已经通过ORDER BY tid DESC LIMIT 1确保只返回最大的tid,所以mock无需模拟多行,直接返回目标值3即可。

修改测试代码中的结果集部分:

rows := sqlmock.NewRows([]string{"tid"}).AddRow(3) // 仅添加最大的tid行

另外注意:你当前用字符串"1"、"3"作为行数据,但目标变量是int类型,直接传入int值更严谨,避免潜在类型转换问题。

问题2:出现sql: expected 2 destination arguments in Scan, not 1错误

这个错误的核心是查询语句返回的列数和Scan传入的参数数量不匹配:

  • 如果你修改了查询语句,比如同时查询tid和cmdline列,但Scan时只传了&id一个参数,就会触发该错误;
  • 若不需要cmdline数据,保持原查询只选择tid即可;
  • 若确实需要获取cmdline,需定义对应变量并传入Scan:
    var id int
    var cmdline string
    err := row.Scan(&id, &cmdline)
    

关于cmdline LIKE条件的校验优化

当前测试代码已能匹配SQL语句,但建议用参数化查询替代字符串拼接,既避免SQL注入风险,也让mock更灵活:

// 待测试函数改为参数化查询
func (y *YumDatabase) getTransactionId(pkg string) (int, error) {
    var id int
    queryForTid := "SELECT tid FROM trans_cmdline WHERE cmdline LIKE $1 ORDER BY tid DESC LIMIT 1"
    row := y.db.QueryRow(queryForTid, "%install "+pkg+"%")
    // ... 后续逻辑不变
}

// 测试代码匹配参数化SQL并设置参数
func TestGetTransactionId(t *testing.T) {
    // ... 初始化mock逻辑不变
    rows := sqlmock.NewRows([]string{"tid"}).AddRow(3)
    mock.ExpectQuery(`SELECT tid FROM trans_cmdline WHERE cmdline LIKE \$1 ORDER BY tid DESC LIMIT 1`).
        WithArgs("%install "+pkg+"%").
        WillReturnRows(rows)
    // ... 断言逻辑不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 11:13:11