模拟使用Go Mongo-Driver和mtest更新操作的UpdateOne的UpdateResult结果

huangapple go评论83阅读模式
英文:

Mock UpdateResult From UpdateOne Using Go Mongo-Driver And mtest

问题

我正在尝试使用mtest包(https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo/integration/mtest)对我的MongoDB调用进行一些测试,并使用模拟结果,但是我似乎无法弄清楚如何正确模拟在集合上进行UpdateOne(...)调用时返回的*mongo.UpdateResult值。

这里是一个演示问题的代码片段:

package test

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
)

func UpdateOneCall(mongoClient *mongo.Client) error {
	filter := bson.D{{Key: "SomeIDField", Value: "SomeID"}}
	update := bson.D{{Key: "$set", Value: bson.D{{Key: "ANewField", Value: true}}}}
	collection := mongoClient.Database("SomeDatabase").Collection("SomeCollection")
	updateResult, err := collection.UpdateOne(context.Background(), filter, update)
	if err != nil {
		return err
	}
	if updateResult.ModifiedCount != 1 {
		return errors.New("no field was updated")
	}
	return nil
}

func TestUpdateOneCall(t *testing.T) {
	mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
	defer mt.Close()

	mt.Run("Successful Update", func(mt *mtest.T) {

		mt.AddMockResponses(mtest.CreateSuccessResponse(
			bson.E{Key: "NModified", Value: 1},
			bson.E{Key: "N", Value: 1},
		))

		err := UpdateOneCall(mt.Client)

		assert.Nil(t, err, "Should have successfully triggered update")
	})
}

collection.UpdateOne(context.Background(), filter, update)调用完全正常。没有返回错误。不幸的是,updateResult.ModifiedCount的值始终为0。

我尝试了多种mtest.CreateSuccessResponse(...)bson.D的组合,使用了NModifiedN等名称(如代码片段中所示),以及ModifiedCountMatchedCount。但是似乎没有什么效果。

有没有办法模拟这个调用,使其实际上返回ModifiedCount的值?

英文:

I'm trying to use the mtest package (https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo/integration/mtest) to perform some testing with mock results on my MongoDB calls, but I can't seem to figure out how to properly mock the *mongo.UpdateResult value that gets returned when you make an UpdateOne(...) call on a collection.

Here is a snippet demonstrating the problem:

package test

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
)

func UpdateOneCall(mongoClient *mongo.Client) error {
	filter := bson.D{{Key: "SomeIDField", Value: "SomeID"}}
	update := bson.D{{Key: "$set", Value: bson.D{{Key: "ANewField", Value: true}}}}
	collection := mongoClient.Database("SomeDatabase").Collection("SomeCollection")
	updateResult, err := collection.UpdateOne(context.Background(), filter, update)
	if err != nil {
		return err
	}
	if updateResult.ModifiedCount != 1 {
		return errors.New("no field was updated")
	}
	return nil
}

func TestUpdateOneCall(t *testing.T) {
	mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
	defer mt.Close()

	mt.Run("Successful Update", func(mt *mtest.T) {

		mt.AddMockResponses(mtest.CreateSuccessResponse(
			bson.E{Key: "NModified", Value: 1},
			bson.E{Key: "N", Value: 1},
		))

		err := UpdateOneCall(mt.Client)

		assert.Nil(t, err, "Should have successfully triggered update")
	})
}

The collection.UpdateOne(context.Background(), filter, update) call works perfectly fine. There are no errors returned. Unfortunately, the updateResult.ModifiedCount value is always 0.

I've tried multiple combinations of mtest.CreateSuccessResponse(...) and bson.D, utilizing names such as NModified and N (as can be seen in the snippet), as well as ModifiedCount and MatchedCount. Nothing seems to do the trick.

Is there anyway to mock this call such that it actually returns a value for the ModifiedCount?

答案1

得分: 2

mt.AddMockResponses(bson.D{
{"ok", 1},
{"nModified", 1},
})

这对我来说有效,可以得到ModifiedCount:1。

英文:
mt.AddMockResponses(bson.D{
{"ok", 1},
{"nModified", 1},
})

This worked for me to get ModifiedCount : 1

答案2

得分: 1

@Vishwas Mallikarjuna给出了正确的答案,所以我将保留他们的帖子作为被接受的答案,因为他们绝对值得。然而,根据他们的发现,我只是想稍微扩展一下。

问题归结为大小写敏感性。现在我知道了这一点,我能够模拟MatchedCountModifiedCountUpsertedCountUpsertedID

以下代码片段展示了如何影响所有这些值:

package test

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
	"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
)

const (
	mockMatchedCount            int64  = 5
	oneLessThanMockedMatchCount int64  = 4
	mockModifiedCount           int64  = 22
	mockUpsertedCount           int64  = 13
	mockUpsertedID              string = "CouldBeAnythingIThink"
)

func UpdateOneCall(mongoClient *mongo.Client) (*mongo.UpdateResult, error) {
	filter := bson.D{{Key: "SomeIDField", Value: "SomeID"}}
	update := bson.D{{Key: "$set", Value: bson.D{{Key: "ANewField", Value: true}}}}
	collection := mongoClient.Database("SomeDatabase").Collection("SomeCollection")
	return collection.UpdateOne(context.Background(), filter, update)
}

func TestUpdateOneCall(t *testing.T) {
	mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
	defer mt.Close()

	mt.Run("Successful Update", func(mt *mtest.T) {

		upsertedVals := make([]operation.Upsert, mockUpsertedCount)
		upsertedVals[0] = operation.Upsert{ID: mockUpsertedID}
		mt.AddMockResponses(mtest.CreateSuccessResponse(
			bson.E{Key: "n", Value: mockMatchedCount},
			bson.E{Key: "nModified", Value: mockModifiedCount},
			bson.E{Key: "upserted", Value: upsertedVals},
		))

		result, err := UpdateOneCall(mt.Client)

		assert.Nil(t, err, "Should have successfully triggered update")
		assert.Equal(t, result.MatchedCount, oneLessThanMockedMatchCount)
		assert.Equal(t, result.ModifiedCount, mockModifiedCount)
		assert.Equal(t, result.UpsertedCount, mockUpsertedCount)
		assert.Equal(t, result.UpsertedID, mockUpsertedID)
	})
}

另外,如果你想知道为什么实际的result.MatchedCountoneLessThanMockedMatchCount,这与Upserted值的工作原理有关。如果你仔细阅读文件go.mongodb.org/mongo-driver@v1.10.2/mongo/collection.go中的逻辑,你会发现以下代码片段对此进行了解释:

opRes := op.Result()
res := &UpdateResult{
	MatchedCount:  opRes.N,
	ModifiedCount: opRes.NModified,
	UpsertedCount: int64(len(opRes.Upserted)),
}
if len(opRes.Upserted) > 0 {
	res.UpsertedID = opRes.Upserted[0].ID
	res.MatchedCount--
}

return res, err
英文:

@Vishwas Mallikarjuna got the right answer, so I'm leaving their post as the accepted one because they absolutely deserve that. However, given their findings, I just wanted to expand a little bit.

The issue came down to case-sensitivity. Now that I know that, I was able to mock the MatchedCount, ModifiedCount, UpsertedCount, and the UpsertedID.

This chunk of code shows how you would go about influencing all of these values:

package test

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/integration/mtest"
	"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
)

const (
	mockMatchedCount            int64  = 5
	oneLessThanMockedMatchCount int64  = 4
	mockModifiedCount           int64  = 22
	mockUpsertedCount           int64  = 13
	mockUpsertedID              string = "CouldBeAnythingIThink"
)

func UpdateOneCall(mongoClient *mongo.Client) (*mongo.UpdateResult, error) {
	filter := bson.D{{Key: "SomeIDField", Value: "SomeID"}}
	update := bson.D{{Key: "$set", Value: bson.D{{Key: "ANewField", Value: true}}}}
	collection := mongoClient.Database("SomeDatabase").Collection("SomeCollection")
	return collection.UpdateOne(context.Background(), filter, update)
}

func TestUpdateOneCall(t *testing.T) {
	mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
	defer mt.Close()

	mt.Run("Successful Update", func(mt *mtest.T) {

		upsertedVals := make([]operation.Upsert, mockUpsertedCount)
		upsertedVals[0] = operation.Upsert{ID: mockUpsertedID}
		mt.AddMockResponses(mtest.CreateSuccessResponse(
			bson.E{Key: "n", Value: mockMatchedCount},
			bson.E{Key: "nModified", Value: mockModifiedCount},
			bson.E{Key: "upserted", Value: upsertedVals},
		))

		result, err := UpdateOneCall(mt.Client)

		assert.Nil(t, err, "Should have successfully triggered update")
		assert.Equal(t, result.MatchedCount, oneLessThanMockedMatchCount)
		assert.Equal(t, result.ModifiedCount, mockModifiedCount)
		assert.Equal(t, result.UpsertedCount, mockUpsertedCount)
		assert.Equal(t, result.UpsertedID, mockUpsertedID)
	})
}

Also, if you're wondering why the actual result.MatchedCount is oneLessThanMockedMatchCount, it comes down to how having an Upserted value works. If you go through the logic, in the file go.mongodb.org/mongo-driver@v1.10.2/mongo/collection.go you'll find this chunk of code that explains it:

opRes := op.Result()
res := &UpdateResult{
	MatchedCount:  opRes.N,
	ModifiedCount: opRes.NModified,
	UpsertedCount: int64(len(opRes.Upserted)),
}
if len(opRes.Upserted) > 0 {
	res.UpsertedID = opRes.Upserted[0].ID
	res.MatchedCount--
}

return res, err

huangapple
  • 本文由 发表于 2022年12月2日 23:37:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/74658175.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定