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

使用go-sqlmock测试Gorm时查询语句匹配失败问题排查

Go-Sqlmock测试Gorm时SQL语句不匹配的正确解决方法

问题根源

从报错信息可以明确看到,Gorm实际生成的SQL是:

SELECT * FROM `transaction` WHERE id = ?

而你测试中预期的正则对应的SQL是:

SELECT * FROM transaction WHERE id = ?;

两者核心差异有两点:

  1. 由于transaction是MySQL保留关键字,Gorm会自动给表名加上反引号进行转义
  2. 实际生成的SQL末尾没有分号,但你预期的语句带了分号

正确匹配方案

不要用regexp.QuoteMeta直接转义整个SQL字符串,而是编写和实际生成SQL完全匹配的正则表达式:

修改测试代码中的ExpectQuery部分

rows := sqlmock.NewRows([]string{"id", "buyer_id", "seller_id", "item_id", "message_id", "expired_date", "created_at"}).
    AddRow(2, 2, 5, 2, 2, "2022-09-10 01:01:00", "2022-09-08 01:01:00")
// 正则里的反引号需要转义,同时去掉末尾的分号
mock.ExpectQuery(regexp.MustCompile(`SELECT \* FROM \`transaction\` WHERE id = \?`)).WillReturnRows(rows)

小技巧:提前获取Gorm生成的准确SQL

如果不确定Gorm生成的SQL格式,可以临时在待测试函数中添加DryRun代码打印SQL:

func (rc repositoryClient) GetTransactionByID(id int) (domain.Transaction, error) {
    trans := domain.Transaction{}
    // 临时添加DryRun打印SQL
    stmt := rc.db.Where("id = ?", id).Find(&trans).Statement
    fmt.Println(stmt.SQL.String()) // 控制台会输出准确的SQL语句
    status := rc.db.Where("id = ?", id).Find(&trans)
    // ... 原有逻辑
}

运行测试后,直接复制控制台输出的SQL,再转成对应的正则即可(只需要转义反引号、问号这类正则特殊字符)。

为什么之前的方法失效

regexp.QuoteMeta会把所有正则特殊字符(包括反引号)都转义,导致你预期的正则中没有表名的反引号;同时你预期的SQL末尾带了分号,而Gorm实际生成的SQL没有分号,这两个点共同导致了匹配失败。

额外注意点

你定义的successGetTransaction中ExpiredDate的值"2022-09-010 01:01:00"存在日期格式错误(多了一个0),建议修正为"2022-09-10 01:01:00",否则即使SQL匹配成功,断言也会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:35:23