求助:Golang中Mock MongoDB驱动示例(含FindOneAndUpdate与索引创建)
使用mtest Mock MongoDB驱动的单元测试示例
基础测试结构
先初始化mtest环境,每个测试用例独立创建实例,避免交叉影响:
package yourrepo import ( "context" "testing" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/integration/mtest" ) func TestYourRepository(t *testing.T) { mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) defer mt.Close() // 编写具体Mock逻辑和测试断言 }
1. Mock collection.Indexes.CreateMany
通过匹配createIndexes命令,模拟索引创建的成功/失败场景:
mt.Run("create indexes success", func(mt *mtest.T) { // 定义预期创建的索引 indexes := []mongo.IndexModel{ { Keys: bson.D{{Key: "email", Value: 1}}, Options: &mongo.IndexOptions{Unique: true}, }, { Keys: bson.D{{Key: "username", Value: 1}}, }, } // 设置Mock响应:返回成功创建2个索引 mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{ {Key: "numIndexesCreated", Value: 2}, })) // 调用你的Repository索引创建方法 err := yourRepo.CreateIndexes(context.TODO(), indexes) if err != nil { t.Fatalf("expected no error, got %v", err) } // 验证是否发送了预期的创建索引命令 mt.ExpectCommands(mtest.CreateIndexesCommand(indexes...)) }) // 模拟索引创建失败场景 mt.Run("create indexes failed", func(mt *mtest.T) { // 设置Mock响应:返回重复索引错误 mt.AddMockResponses(mtest.CreateWriteErrorResponse( mtest.WriteError{Code: 11000, Message: "duplicate index exists"}, )) err := yourRepo.CreateIndexes(context.TODO(), []mongo.IndexModel{}) if err == nil { t.Fatal("expected error, got nil") } })
2. Mock collection.FindOneAndUpdate
匹配findAndModify命令,模拟更新并返回结果:
mt.Run("find one and update success", func(mt *mtest.T) { filter := bson.M{"_id": "user123"} update := bson.M{"$set": bson.M{"status": "active"}} updatedUser := bson.M{"_id": "user123", "name": "Alice", "status": "active"} // 设置Mock响应:返回更新后的文档 mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{ {Key: "value", Value: updatedUser}, })) // 调用你的Repository更新方法 user, err := yourRepo.UpdateUserStatus(context.TODO(), filter, update) if err != nil { t.Fatalf("expected no error, got %v", err) } // 断言返回结果正确性 if user["status"] != "active" { t.Fatalf("expected status 'active', got %v", user["status"]) } // 验证命令参数是否符合预期 mt.ExpectCommands(mtest.FindOneAndUpdateCommand(filter, update)) })
3. 其他方法的Mock示例
Mock collection.Find + cursor.All
模拟游标返回多文档的场景:
mt.Run("find documents success", func(mt *mtest.T) { // 定义要返回的文档列表 docs := []bson.M{ {"_id": "1", "name": "Alice"}, {"_id": "2", "name": "Bob"}, } // 设置Mock响应:先返回游标,再返回文档批次,最后标记游标结束 mt.AddMockResponses( mtest.CreateCursorResponse(1, "testdb.users", mtest.FirstBatch, docs...), mtest.CreateCursorResponse(0, "testdb.users", mtest.NextBatch), ) // 调用你的Repository查询方法 users, err := yourRepo.GetUsers(context.TODO(), bson.M{}) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(users) != 2 { t.Fatalf("expected 2 users, got %d", len(users)) } })
Mock collection.InsertOne
模拟单文档插入并返回ID:
mt.Run("insert one success", func(mt *mtest.T) { user := bson.M{"name": "Charlie"} insertedID := "user456" // 设置Mock响应:返回插入成功的ID mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{ {Key: "insertedId", Value: insertedID}, })) // 调用你的Repository插入方法 id, err := yourRepo.CreateUser(context.TODO(), user) if err != nil { t.Fatalf("expected no error, got %v", err) } if id != insertedID { t.Fatalf("expected inserted ID %s, got %s", insertedID, id) } mt.ExpectCommands(mtest.InsertOneCommand(user)) })
关键注意事项
- 使用
mt.ExpectCommands可验证代码是否发送了预期的MongoDB命令,避免逻辑偏差 - 复杂参数匹配可使用
mtest.MatchDocument或自定义匹配器;无需严格匹配时,用mtest.Anything作为占位符 - 每个
mt.Run是独立测试子用例,Mock响应和命令预期相互隔离
内容的提问来源于stack exchange,提问作者ns.altun
相关产品推荐
相关产品推荐

