我有一个GORM删除,返回的结果是:

expirationDate := time.Now().UTC().Add(-(48 * time.hour))
var deletedUsers Users
res := gormDB.WithContext(ctx).
    Table("my_users").
    Clauses(clause.Returning{Columns: []clause.Column{{Name: "email"}}}).
    Where("created_at < ?", expirationDate).
    Delete(&deletedUsers)

现在,带子句的测试总是失败.例如:

sqlMock.ExpectExec(`DELETE`)
    .WithArgs(expirationDate)
    .WillReturnResult(sqlmock.NewResult(1, 1))

接收错误:

"不应调用查询‘DELETE FROM"MY_USERS"WHERE CREATED_AT&lt;$1返回带有参数[{NAME:ORDERAL:1 VALUE:2023-01-18 06:15:34.694274+0000UTC}]的邮箱,下一个期望是:ExpetedExec=&gt;预期执行或执行上下文:\n-与SQL:‘DELETE’匹配\n-使用参数:\n 0-2023-01-18 06:15:34.694274+0000UTC\n-应返回具有以下内容的结果:\n上次插入ID:1\n受影响的行:1"

我try 了许多其他的sqlMock Expect,但它们都有类似的问题. 此外,我们在ExspectExec中没有返回值,只有在ExspectQuery中才有返回值... 有没有可能需要有人用这些子句测试GORM查询?

推荐答案

我能够成功地满足您的需求.首先,让我共享我编写的文件,然后我将向您介绍所有相关的更改.用于生产的文件为repo.go个,用于测试代码的文件为repo_test.go个.

repo.go

package gormdelete

import (
    "context"
    "time"

    "gorm.io/gorm"
    "gorm.io/gorm/clause"
)

type Users struct {
    Email string
}

func Delete(ctx context.Context, gormDB *gorm.DB) error {
    expirationDate := time.Now().UTC().Add(-(48 * time.Hour))

    var deletedUsers Users
    res := gormDB.WithContext(ctx).Table("my_users").Clauses(clause.Returning{Columns: []clause.Column{{Name: "email"}}}).Where("created_at < ?", expirationDate).Delete(&deletedUsers)
    if res.Error != nil {
        return res.Error
    }
    return nil
}

由于你没有提供完整的文件,我试着猜测遗漏了什么.

repo_test.go

package gormdelete

import (
    "context"
    "database/sql/driver"
    "testing"
    "time"

    "github.com/DATA-DOG/go-sqlmock"
    "github.com/stretchr/testify/assert"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

// this is taken directly from the docs
// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime
type AnyTime struct{}

// Match satisfies sqlmock.Argument interface
func (a AnyTime) Match(v driver.Value) bool {
    _, ok := v.(time.Time)
    return ok
}

func TestDelete(t *testing.T) {
    db, mock, err := sqlmock.New()
    if err != nil {
        t.Fatalf("an error was not expected: %v", err)
    }

    conn, _ := db.Conn(context.Background())
    gormDb, err := gorm.Open(postgres.New(postgres.Config{
        Conn: conn,
    }))

    row := sqlmock.NewRows([]string{"email"}).AddRow("test@example.com")
    mock.ExpectBegin()
    mock.ExpectQuery("DELETE FROM \"my_users\" WHERE created_at < ?").WithArgs(AnyTime{}).WillReturnRows(row)
    mock.ExpectCommit()

    err = Delete(context.Background(), gormDb)

    assert.Nil(t, err)
    if err = mock.ExpectationsWereMet(); err != nil {
        t.Errorf("not all expectations were met: %v", err)
    }
}

在这里,有更多的变化值得一提:

  1. 我按照文档实例化了AnyTime(您可以在注释中看到链接).
  2. 我再一次猜测了dbmockgormDb的设置,但我认为它们应该大致相同.
  3. 我将ExpectExec的用法改为ExpectQuery,因为我们将得到由您的repo.go文件中的Clauses方法指定的结果集.
  4. 你必须把ExpectQuery包在ExpectBeginExpectCommit里.
  5. 最后,注意驱动程序期望SQL语句中的参数的不同之处.在产品代码中,您可以 Select 使用?$1.然而,在测试代码中,您只能使用?,否则它将不符合预期.

希望能帮上一点忙,不然的话,让我知道!

Go相关问答推荐

Go编译器标志-修剪路径不完全工作

消费者在NAT中是如何实现的

Zitadel示例Go Webapp加密密钥

在Golang中,@LATEST和@UPGRADE特殊查询有什么不同?

如何使用Gorilla WebSockets实现Http.Hijacker&;alexedwards/scs/v2

如何使用GO GIN从Auth0 JWT内标识检索权限

Golang中的泛型 struct /接口列表

Redis:尽管数据存在,但 rdb.Pipelined 中出现redis:nil错误

有没有办法让sqlc生成可以使用pgxpool的代码

如何创建在responseWriter.Write 上返回错误的http.ResponseWriter 模拟实例?

Go Gin:验证 base64

在 Go 中将元数据从一个 JPEG 复制到另一个

GitHub 中 REST API 的 aws 凭证问题

在 Golang 中,如何将接口作为泛型类型与 nil 进行比较?

如何通过组合来自不同包的接口来创建接口?

Golang ACMEv2 HTTP-01 挑战不挑战服务器

从 Go struct 中提取标签作为 reflect.Value

Golang 有类似 C++ 的 decltype 的东西吗?

如何使用 httputil.ReverseProxy 设置 X-Forwarded-For

Golang 与 Cassandra db 使用 docker-compose:cannot connect (gocql)