sqlmock与查询不匹配,但是查询相同,并且日志输出显示相同

问题描述 投票:1回答:1

我正在尝试使用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)

任何人都知道我在做什么错吗?

go go-gorm go-sqlmock
1个回答
0
投票

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。这使测试变得不那么脆弱。同时,我们还在此测试中进行了大量检查以验证代码执行流程:

  1. SQL参数数量
  2. 这些SQL参数的值
  3. 确保使用嘲笑.ExpectationsWereMet()执行SQL命令>
  4. 最重要的是,我们必须对SQL查询运行集成测试。这是确保我们的SQL正确并与最新的数据库更改保持最新的唯一方法。

    P.S。避免选择*。使用字段名称明确。

© www.soinside.com 2019 - 2024. All rights reserved.