I am trying to mock the mongoDB function Aggregate
but it keeps returning the generic error of command failed
.
If anyone is interested there is a nice blog about the other functions and how to mock them Mock mongo-go-driver.
Function being tested
func (b *BlogsRepo) CountTagsInBlogs(ctx context.Context) (map[string]int, error) {
clog := log.GetLoggerFromContext(ctx)
// Specify the pipeline to group and count tags
pipeline := []bson.M{
{
"$unwind": "$tags",
},
{
"$group": bson.M{
"_id": "$tags",
"count": bson.M{"$sum": 1},
},
},
}
// Aggregate the data based on the pipeline
cursor, err := b.collection.Aggregate(ctx, pipeline)
if err != nil {
clog.ErrorCtx(err, log.Ctx{
"msg": "Error aggregating data",
"err": err,
})
return nil, err
}
defer cursor.Close(ctx)
// Create a map to store tag counts
tagCounts := make(map[string]int)
// Iterate through the results and populate the map
for cursor.Next(ctx) {
var result struct {
Tag string `bson:"_id"`
Count int `bson:"count"`
}
if err := cursor.Decode(&result); err != nil {
clog.ErrorCtx(err, log.Ctx{
"msg": "Error decoding result"},
)
return nil, err
}
tagCounts[result.Tag] = result.Count
}
return tagCounts, nil
}
test
func TestBlogsRepo_CountTagsInBlogs(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
defer mt.Close()
ctx := context.TODO()
testCases := []struct {
name string
mockedResponse []bson.D
expected map[string]int
err error
}{
{
name: "successful count tags response",
mockedResponse: []bson.D{
{{"_id", "java"}, {"count", 3}},
{{"_id", "go"}, {"count", 7}},
{{"_id", "kotlin"}, {"count", 3}},
},
expected: map[string]int{
"java": 3,
"go": 7,
"kotlin": 3,
},
err: nil,
},
}
for _, tc := range testCases {
tc := tc
mt.Run(tc.name, func(mt *mtest.T) {
// Mock the aggregation response
mt.AddMockResponses(tc.mockedResponse...)
blogRepo := NewBlogRepository(mt.Client, mt.Coll)
// Call the method being tested
tagCounts, err := blogRepo.CountTagsInBlogs(ctx)
// Check the returned values against the expected values
assert.Equal(t, tc.expected, tagCounts, "Tag counts do not match expected values")
assert.NoError(t, err)
})
}
}
Error:
Error: Received unexpected error:
command failed
Test: TestBlogsRepo_CountTagsInBlogs
There is a second error but, it is just because the error is caught, and the map returned is nil
and doesn't match the expected result.
The error occurs here
cursor, err := b.collection.Aggregate(ctx, pipeline)
if err != nil {
clog.ErrorCtx(err, log.Ctx{
"msg": "Error aggregating data",
"err": err,
})
return nil, err
}
defer cursor.Close(ctx)
The mock looks correct. Any advice would be appreciated.
To mock the response of a Collection.Aggregate()
call, you have to create and use a cursor response with mtest.CreateCursorResponse()
.
So do it like this:
for i, tc := range testCases {
tc := tc
mt.Run(tc.name, func(mt *mtest.T) {
// Mock the aggregation response
mt.AddMockResponses(mtest.CreateCursorResponse(
0,
fmt.Sprintf("%s.%d", tc.name, i),
mtest.FirstBatch,
tc.mockedResponse...,
))