使用DATA-DOG/sqlmock测试GORM接口时出现ExpectedBegin报错如何解决
问题产生原因
- 预期执行顺序和GORM实际执行逻辑不匹配:GORM默认仅对
Save/Update等写操作自动开启事务,First类读操作不会触发事务。你当前的预期顺序在用户更新提交事务后,先预期了Begin操作,但实际业务代码下一步执行的是user_profiles表的读查询,不会触发事务开启,sqlmock收到查询请求时和下一个预期的Begin不匹配,直接报错。 - SQL匹配规则错误:你使用
regexp.QuoteMeta全匹配查询语句,但GORM生成的user_profiles查询语句末尾会自动拼接ORDER BY "user_profiles"."id" LIMIT 1后缀,全匹配会导致匹配失败。 - 预期配置不全:你漏了
user_profiles保存操作对应的事务、执行语句、提交的预期配置。
解决方案
1. 调整预期执行顺序
按照业务代码实际执行流配置预期,正确顺序如下:
- 匹配
users表查询请求(读操作,无事务) - 匹配用户保存的事务开启、执行更新、事务提交
- 匹配
user_profiles表查询请求(读操作,无事务) - 匹配用户配置保存的事务开启、执行更新、事务提交
2. 修正SQL匹配规则
不用全量匹配SQL,改用前缀匹配规避GORM自动生成的后缀带来的匹配问题。
3. 补全所有操作的预期配置
修正后的测试mock部分代码参考:
// 1. 预期查询用户 mock.ExpectQuery(regexp.MustCompile(`SELECT * FROM "users" WHERE email = \$1`)). WithArgs("email"). WillReturnRows(rows) // 2. 预期保存用户的事务流程 mock.ExpectBegin() mock.ExpectExec(regexp.MustCompile(`UPDATE "users"`)). WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // 3. 预期查询用户配置(无事务,直接匹配查询) mock.ExpectQuery(regexp.MustCompile(`SELECT * FROM "user_profiles" WHERE email = \$1 AND provider = \$2 AND external_user_id = \$3`)). WithArgs("email", "provider", "testID"). WillReturnRows(profileRows) // 4. 预期保存用户配置的事务流程 mock.ExpectBegin() mock.ExpectExec(regexp.MustCompile(`UPDATE "user_profiles"`)). WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // 测试逻辑执行完后追加预期校验,排查遗漏的预期 if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("未满足所有mock预期: %s", err) }
内容的提问来源于stack exchange,提问作者rak1n
相关产品推荐
相关产品推荐

