
php小编新一为您介绍Gorm删除子句sqlmock测试。Gorm是Go语言中一款优秀的ORM框架,而sqlmock是Gorm的一个测试工具,用于模拟数据库操作。在进行Gorm开发时,我们经常需要进行数据库删除操作的测试,这时候就可以使用sqlmock来模拟数据库的删除操作,以便进行单元测试和集成测试。本文将为您详细介绍如何使用Gorm和sqlmock进行删除子句的测试,帮助您更好地进行数据库相关的开发工作。
问题内容
我有一个 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))
接收错误:
“使用参数 [{name: ordinal:1 value:2023-01-18 06:15:34.694274 +0000 utc}] 调用查询 'delete from "my_users" where created_at 期望 exec 或 execcontext 其中:\n - 匹配 sql:'delete'\n - 带有参数:\n 0 - 2023-01-18 06:15:34.694274 +0000 utc\ n - 应返回具有以下内容的结果:\n lastinsertid: 1\n rowsaffected: 1"
我尝试了许多其他 sqlmock 期望,但他们也有类似的问题。 另外,我们在 expectexec 中没有返回值,只有在 expectquery 中... 有人必须用子句测试 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("[email protected]")
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)
}
}
这里还有更多值得一提的变化:
- 我根据文档实例化了
anytime(您可以在评论中看到链接)。 - 我再次猜测了
db、mock和gormdb的设置,但我认为它们应该大致相同。 - 我将
expectexec的用法切换为expectquery,因为我们将返回clauses文件中repo.go方法指定的结果集。 - 您必须将
expectquery包装在expectbegin和expectcommit中。 - 最后,请注意驱动程序对 sql 语句中参数的期望方式的差异。在生产代码中,您可以选择使用
?或$1。但在测试代码中,只能使用?,否则不符合预期。
希望能帮上一点忙,否则请告诉我!










