You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:23:12