在 Go 中模拟 MongoDB 响应

我正在从 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{}类型。


慕妹3146593
浏览 136回答 3
3回答

郎朗坤

我认为您可以尝试类似以下的操作(当然,您可能需要对此进行调整和实验):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 容器的集成测试以自动化的方式执行更真实的测试。

万千封印

编写可测试的最佳解决方案可能是将代码提取到 DAO 或数据存储库。您将定义一个接口来返回您需要的内容。这样,您就可以使用模拟版本进行测试。// repository.gotype 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.gotype 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 传递到函数中。

胡说叔叔

使用 Monkey 库来挂钩 mongo 驱动程序中的任何函数。例如:func insert(collection *mongo.Collection) (int, error) {&nbsp; &nbsp; ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)&nbsp; &nbsp; u := User{&nbsp; &nbsp; &nbsp; &nbsp; Name: "kevin",&nbsp; &nbsp; &nbsp; &nbsp; Age:&nbsp; 20,&nbsp; &nbsp; }&nbsp; &nbsp; res, err := collection.InsertOne(ctx, u)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Printf("error: %v", err)&nbsp; &nbsp; &nbsp; &nbsp; return 0, err&nbsp; &nbsp; }&nbsp; &nbsp; id := res.InsertedID.(int)&nbsp; &nbsp; return id, nil}func TestInsert(t *testing.T) {&nbsp; &nbsp; var c *mongo.Collection&nbsp; &nbsp; var guard *monkey.PatchGuard&nbsp; &nbsp; guard = monkey.PatchInstanceMethod(reflect.TypeOf(c), "InsertOne",&nbsp; &nbsp; &nbsp; &nbsp; func(c *mongo.Collection, ctx context.Context, document interface{}, opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; guard.Unpatch()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer guard.Restore()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Printf("record: %+v, collection: %s, database: %s", document, c.Name(), c.Database().Name())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res := &mongo.InsertOneResult{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InsertedID: 100,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return res, nil&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; collection := client.Database("db").Collection("person")&nbsp; &nbsp; id, err := insert(collection)&nbsp; &nbsp; require.NoError(t, err)&nbsp; &nbsp; assert.Equal(t, id, 100)}
打开App,查看更多内容
随时随地看视频慕课网APP