英文:
call to Rollback transaction, was not expected, next expectation is: ExpectedQuery
问题
我正在尝试编写下面的测试,其他测试都正常工作,但是我在UPDATE
查询方面遇到了问题。
func TestDeleteWorkspace(t *testing.T) {
conn, mock, repository, err := setup()
defer conn.Close()
assert.NoError(t, err)
uid := uuid.New()
// mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "workspaces" SET`)).WithArgs(sqlmock.AnyArg(), uid)
// mock.ExpectCommit()
var e bool
e, err = repository.Delete(uid)
assert.NoError(t, err)
assert.True(t, e)
err = mock.ExpectationsWereMet()
assert.NoError(t, err)
}
repository.Delete
执行了这个查询:
func (r *WorkspaceRepository) Delete(id any) (bool, error) {
if err := r.db.Delete(&model.Workspace{}, "id = ?", id).Error; err != nil {
return false, nil
}
return true, nil
}
它运行了这个查询:
UPDATE "workspaces" SET "deleted_at"='2022-07-04 09:09:20.778' WHERE id = 'c4610193-b43a-4ed7-9ed6-9d67b3f97502' AND "workspaces"."deleted_at" IS NULL
我正在使用软删除,所以是一个UPDATE查询而不是DELETE查询。
然而,我得到了以下错误:
workspace_test.go:169:
Error Trace: workspace_test.go:169
Error: Received unexpected error:
there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
- matches sql: 'UPDATE "workspaces" SET'
- is with arguments:
0 - 28e7aa46-7a22-4dc7-b3ce-6cf02af525ca
1 - {}
我做错了什么?
编辑:这是一个软删除操作,所以是UPDATE而不是DELETE。
我的模型:
type Workspace struct {
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()" json:"id"`
Name string `gorm:"not null,type:text" json:"name"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"create_time"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"update_time"`
DeletedAt gorm.DeletedAt `gorm:"index->" json:"-"`
}
英文:
I am trying to wrote this test bellow, other tests works fine, however I am having problems with the UPDATE
query
func TestDeleteWorkspace(t *testing.T) {
conn, mock, repository, err := setup()
defer conn.Close()
assert.NoError(t, err)
uid := uuid.New()
// mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`UPDATE "workspaces" SET`)).WithArgs(sqlmock.AnyArg(), uid)
// mock.ExpectCommit()
var e bool
e, err = repository.Delete(uid)
assert.NoError(t, err)
assert.True(t, e)
err = mock.ExpectationsWereMet()
assert.NoError(t, err)
}
repository.Delete
does this query
func (r *WorkspaceRepository) Delete(id any) (bool, error) {
if err := r.db.Delete(&model.Workspace{}, "id = ?", id).Error; err != nil {
return false, nil
}
return true, nil
}
Which runs this query
UPDATE "workspaces" SET "deleted_at"='2022-07-04 09:09:20.778' WHERE id = 'c4610193-b43a-4ed7-9ed6-9d67b3f97502' AND "workspaces"."deleted_at" IS NULL
I am using Soft-Delete, that is why it is an UPDATE and not a DELETE query
However, I get the following error
workspace_test.go:169:
Error Trace: workspace_test.go:169
Error: Received unexpected error:
there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:
- matches sql: 'UPDATE "workspaces" SET'
- is with arguments:
0 - 28e7aa46-7a22-4dc7-b3ce-6cf02af525ca
1 - {}
What I am doing wrong?
EDIT: It is a soft-delete operation, that why is a UPDATE and not a DELETE
My model
type Workspace struct {
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()" json:"id"`
Name string `gorm:"not null,type:text" json:"name"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"create_time"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"update_time"`
DeletedAt gorm.DeletedAt `gorm:"index,->" json:"-"`
}
答案1
得分: 1
错误消息相当自解释。
这是你的查询语句:
'UPDATE "workspaces" SET "deleted_at"=$1 WHERE id = $2 AND "workspaces"."deleted_at" IS NULL'
它包含两个参数:
"deleted_at"=$1 WHERE id = $2
你在 SQL 模拟中只设置了一个参数:
.WithArgs(uid)
你需要在模拟中发送两个参数。
在测试中使用 Time.Now()
不可靠,因为该值偶尔会与你在代码中设置的值相差几纳秒,导致测试失败。
一个快速而简单的解决方法是使用 sqlmock.AnyArg()
:
.WithArgs(sqlmock.AnyArg(), uid)
一个更复杂的替代方法是编写自定义的 Argument
,它检查类型并将值与 time.Now()
进行比较。差异应该小于几秒钟。
参考示例:https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime
英文:
Error message is quite self-explanatory.
This is your query:
'UPDATE "workspaces" SET "deleted_at"=$1 WHERE id = $2 AND "workspaces"."deleted_at" IS NULL'
it includes 2 arguments:
"deleted_at"=$1 WHERE id = $2
You set only 1 in your SQL mock:
.WithArgs(uid)
You need to send both arguments in mock.
It is not reliable to use Time.Now()
in test because that value occasionally is going to be a few nanoseconds different from the value you set in code and test will fail.
The quick and dirty fix is to use sqlmock.AnyArg()
:
.WithArgs(sqlmock.AnyArg(), uid)
A more sophisticated alternative is to write custom Argument
that checks type and compares value with time.Now()
. Difference should be less than a few seconds.
See an example: https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论