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?
@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/[email protected]/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
mt.AddMockResponses(bson.D{
{"ok", 1},
{"nModified", 1},
})
This worked for me to get ModifiedCount : 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With