英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论