为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中模拟 MongoDB 响应

在 Go 中模拟 MongoDB 响应

Go
慕妹3146593 2023-06-26 17:32:59
我正在从 MongoDB 获取文档并将其传递给函数transform,例如var doc map[string]interface{}err := collection.FindOne(context.TODO(), filter).Decode(&doc) result := transform(doc)我想为 编写单元测试transform,但我不确定如何模拟来自 MongoDB 的响应。理想情况下我想设置这样的东西:func TestTransform(t *testing.T) {    byt := []byte(`    {"hello": "world",     "message": "apple"} `)    var doc map[string]interface{}    >>> Some method here to Decode byt into doc like the code above <<<    out := transform(doc)    expected := ...    if diff := deep.Equal(expected, out); diff != nil {        t.Error(diff)    }}一种方法是json.Unmarshalinto doc,但这有时会产生不同的结果。例如,如果 MongoDB 中的文档中有一个数组,那么该数组将被解码为doc类型bson.A而不是[]interface{}类型。
查看完整描述

3 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

我认为您可以尝试类似以下的操作(当然,您可能需要对此进行调整和实验):

func TestTransform(t *testing.T) {

    mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))

    defer mt.Close()


    mt.Run("find & transform", func(mt *mtest.T) {

        myollection = mt.Coll

        expected := myStructure{...}


        mt.AddMockResponses(mtest.CreateCursorResponse(1, "foo.bar", mtest.FirstBatch, bson.D{

            {"_id", expected.ID},

            {"field-1", expected.Field1},

            {"field-2", expected.Field2},

        }))


        response, err := myFindFunction(expected.ID)

        if err != nil {

            t.Error(err)

        }


        out := transform(response)

        if diff := deep.Equal(expected, out); diff != nil {

            t.Error(diff)

        }

    })

}

或者,您可以通过与 Docker 容器的集成测试以自动化的方式执行更真实的测试。

查看完整回答
反对 回复 2023-06-26
?
万千封印

TA贡献1891条经验 获得超3个赞

编写可测试的最佳解决方案可能是将代码提取到 DAO 或数据存储库。您将定义一个接口来返回您需要的内容。这样,您就可以使用模拟版本进行测试。


// repository.go

type ISomeRepository interface {

    Get(string) (*SomeModel, error)

}


type SomeRepository struct { ... }


func (r *SomeRepository) Get(id string) (*SomeModel, error) {

    // Handling a real repository access and returning your Object

}

当你需要模拟它时,只需创建一个 Mock-Struct 并实现接口:


// repository_test.go


type SomeMockRepository struct { ... }


func (r *SomeRepository) Get(id string) (*SomeModel, error) {

    return &SomeModel{...}, nil

}


func TestSomething() {

    // You can use your mock as ISomeRepository

    var repo *ISomeRepository

    repo = &SomeMockRepository{}

    someModel, err := repo.Get("123")

}

这最好与某种依赖注入一起使用,因此将此存储库作为 ISomeRepository 传递到函数中。



查看完整回答
反对 回复 2023-06-26
?
胡说叔叔

TA贡献1804条经验 获得超8个赞

使用 Monkey 库来挂钩 mongo 驱动程序中的任何函数。


例如:


func insert(collection *mongo.Collection) (int, error) {

    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)


    u := User{

        Name: "kevin",

        Age:  20,

    }


    res, err := collection.InsertOne(ctx, u)

    if err != nil {

        log.Printf("error: %v", err)

        return 0, err

    }


    id := res.InsertedID.(int)

    return id, nil

}


func TestInsert(t *testing.T) {

    var c *mongo.Collection


    var guard *monkey.PatchGuard

    guard = monkey.PatchInstanceMethod(reflect.TypeOf(c), "InsertOne",

        func(c *mongo.Collection, ctx context.Context, document interface{}, opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) {

            guard.Unpatch()

            defer guard.Restore()


            log.Printf("record: %+v, collection: %s, database: %s", document, c.Name(), c.Database().Name())

            res := &mongo.InsertOneResult{

                InsertedID: 100,

            }


            return res, nil

        })


    collection := client.Database("db").Collection("person")

    id, err := insert(collection)


    require.NoError(t, err)

    assert.Equal(t, id, 100)

}


查看完整回答
反对 回复 2023-06-26
  • 3 回答
  • 0 关注
  • 182 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信