英文:
How mock mongo.ErrNoDocuments with mtest in Golang
问题
我有这个函数:
func CheckExistUser(documentNumber string, mongoClient *mongo.Database) error {
ctx := context.Background()
colletionUsersName := "my-collection"
colletionUsers := mongoClient.Collection(colletionUsersName)
filter := bson.D{{Key: "cpf", Value: documentNumber}}
user := &entity.UserEntity{}
err := colletionUsers.FindOne(ctx, filter).Decode(user)
if err == mongo.ErrNoDocuments { // 这里有未覆盖的测试
return models.ErrAccountNotFound // 这里有未覆盖的测试
}
if err != nil {
return err
}
return nil
}
我想测试这一行 if err == mongo.ErrNoDocuments
。我创建了一个模拟通用错误和成功的测试。
这是我的通用错误测试:
func TestFindOneWhenMongoReturnsError(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
defer mt.Close()
mt.Run("success", func(mt *mtest.T) {
fakeError := mtest.WriteError{
Index: 1,
Code: 200,
Message: "mongo中的通用错误",
}
mt.AddMockResponses(mtest.CreateWriteErrorsResponse(fakeError))
documentNumber := "12345678900"
err := repository.CheckExistUser(documentNumber, mt.Client.Database("mongodb://mock"))
assert.ErrorContains(t, err, fakeError.Message)
})
}
这个测试非常顺利。但只适用于以下代码:
if err != nil {
return err
}
我无法使函数 FindOne
返回 mongo.ErrNoDocuments
实例。我该如何测试这一行:
if err == mongo.ErrNoDocuments {
英文:
I have this function:
func CheckExistUser(documentNumber string, mongoClient *mongo.Database) error {
ctx := context.Background()
colletionUsersName := "my-collection"
colletionUsers := mongoClient.Collection(colletionUsersName
filter := bson.D{{Key: "cpf", Value: documentNumber}}
user := &entity.UserEntity{}
err := colletionUsers.FindOne(ctx, filter).Decode(user)
if err == mongo.ErrNoDocuments { // uncovered test here
return models.ErrAccountNotFound // uncovered test here
}
if err != nil {
return err
}
return nil
}
I want to test the line if err == mongo.ErrNoDocument
. I made a test mocking generic error and success.
This is my generic error test
func TestFindOneWhenMongoReturnsError(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
defer mt.Close()
mt.Run("success", func(mt *mtest.T) {
fakeError := mtest.WriteError{
Index: 1,
Code: 200,
Message: "generic error in mongo",
}
mt.AddMockResponses(mtest.CreateWriteErrorsResponse(fakeError))
documentNumber := "12345678900"
err := repository.CheckExistUser(documentNumber, mt.Client.Database("mongodb://mock"))
assert.ErrorContains(t, err, fakeError.Message)
})
}
This works like a charm. But work only for these lines
if err != nil {
return err
}
I cannot make the function FindOne
return the instance mongo.ErrNoDocuments
.
How can I do to test this line:
if err == mongo.ErrNoDocuments {
答案1
得分: 2
要模拟Collection.FindOne()
调用的结果,您需要创建和使用一个游标响应,其中包含一个批次(结果文档的列表),并且该批次应该是空的。(FindOne()
操作也是一个带有隐式limit=1
的Find()
操作。)
以下是使用mtest.CreateCursorResponse()
的方法:
mt.AddMockResponses(mtest.CreateCursorResponse(
0,
fmt.Sprintf("%s.%s", "dbName", "collName"),
mtest.FirstBatch,
// 这里故意没有列出文档
))
如果您希望游标包含/返回文档,则可以将它们列为最后一个可变参数。在这里,我故意将其留空,以便游标不返回任何元素。
这将导致FindOne()
返回mongo.ErrNoDocuments
。
以下是一个完整的测试示例:
func TestFindOneWhenUserDoesntExist(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
defer mt.Close()
mt.Run("ErrAccountNotFound", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateCursorResponse(
0,
fmt.Sprintf("%s.%s", "dbName", "collName"),
mtest.FirstBatch,
// 这里故意没有列出文档
))
documentNumber := "12345678900"
err := CheckExistUser(documentNumber, mt.Client.Database("mongodb://mock"))
assert.ErrorIs(t, err, models.ErrAccountNotFound)
})
}
这里有一个包含更多使用mtest
的示例的页面:https://medium.com/@victor.neuret/mocking-the-official-mongo-golang-driver-5aad5b226a78
英文:
To mock the result of a Collection.FindOne()
call, you (also) have to create and use a cursor response, composed of a single batch of course, and the batch (list of result documents) should be empty. (A FindOne()
operation is also a Find()
operation with an implicit limit=1
.)
Here's how you can do it using mtest.CreateCursorResponse()
:
mt.AddMockResponses(mtest.CreateCursorResponse(
0,
fmt.Sprintf("%s.%s", "dbName", "collName"),
mtest.FirstBatch,
// no documents listed here on purpose
))
If you would want the cursor to contain / return documents those could be listed as the final variadic argument, here I intentionally left that empty, so the cursor will return no elements.
This will result in FindOne()
returning mongo.ErrNoDocuments
.
Here's a complete test:
func TestFindOneWhenUserDoesntExist(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
defer mt.Close()
mt.Run("ErrAccountNotFound", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateCursorResponse(
0,
fmt.Sprintf("%s.%s", "dbName", "collName"),
mtest.FirstBatch,
// no documents listed here on purpose
))
documentNumber := "12345678900"
err := CheckExistUser(documentNumber, mt.Client.Database("mongodb://mock"))
assert.ErrorIs(t, err, models.ErrAccountNotFound)
})
}
Here's a page with many more examples of using mtest
: https://medium.com/@victor.neuret/mocking-the-official-mongo-golang-driver-5aad5b226a78
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论