我正在尝试使用sqlmock使用Gorm编写一些代码的测试。我想出了为插入功能编写测试的方法,但现在我想尽办法使更新生效。
工作流的第一部分只是从数据库查询记录。即使日志输出显示它们相同,我也无法使其与我的SQL相匹配。
这里是错误消息:
(/path/to/my/project/database.go:263)
[2020-01-08 10:29:40] Query: could not match actual sql: "SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1" with expected regexp "SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1"
我也尝试过使用ExpectQuery的ExpectExec插入。
for _, c := range cases {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
DB, err := gorm.Open("sqlite3", db)
if err != nil {
t.Fatal(err)
}
DB.LogMode(true)
mock.ExpectQuery(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1`)
err = UpdateStoragePool(DB, &c.givenPool)
if !reflect.DeepEqual(c.wantedError, err) {
t.Fatalf("expecting errror %q, got %q", c.wantedError, err)
}
// if we didn't have any errors during the tx, check all expectations were met
if c.wantedError == nil {
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf(err.Error())
}
}
}
我也尝试过:
mock.ExpectQuery(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = '1')) ORDER BY "storage_pools"."id" ASC LIMIT 1`).WithArgs(1)
mock.ExpectExec(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1`)
mock.ExpectExec(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = '1')) ORDER BY "storage_pools"."id" ASC LIMIT 1`).WithArgs(1)
任何人都知道我在做什么错吗?
mock.ExpectExec()
函数不执行简单的字符串比较。相反,它使用输入字符串作为RegExp来匹配查询。
SQL匹配字符串中的某些字符是保留的RegExp字符,应转义以匹配SQL。
转义后您的字符串应如下所示:
SELECT \* FROM "storage_pools" WHERE "storage_pools"\."deleted_at" IS NULL AND \(\(poolid \= \?\)\) ORDER BY "storage_pools"\."id" ASC LIMIT 1
提示:您可以使用https://www.regex-escape.com/preg_quote-online.php或其他网站在线转义字符串>
[附加思想:完全匹配SQL的测试可能很脆弱,而不必为完全匹配SQL添加太多额外的价值。
如果任何人进行无害更改(例如添加多余的空格字符),测试都会给您带来假阳性结果。另一方面,全文匹配不能捕获与SQL不兼容的数据库架构更改。
我最终为我的项目完成了此设置:
mock.ExpectExec()
的运行单元测试带有基本的子字符串,例如INSERT INTO history
。这使测试变得不那么脆弱。同时,我们还在此测试中进行了大量检查以验证代码执行流程:
最重要的是,我们必须对SQL查询运行集成测试。这是确保我们的SQL正确并与最新的数据库更改保持最新的唯一方法。
P.S。避免选择*
。使用字段名称明确。