How to mock mongo with this interface? #30
-
If I have the following code mycollection := mongo.Database("mydb").Collection("mycollection") How can I mock FindOne and specify what data should be decoded into "record" ? If I were to do that for another 50 db calls, is it possible to establish what a specific call should be returning when the test is run? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
oh, thank you. It is very good question. But before answer let me add the mocks to this repo, I think it will be much easier if the repo will contain mocks as well |
Beta Was this translation helpful? Give feedback.
-
OK. Here is an example of how to mock the mongo objects Let's say we have a function that returns all admin users: package simple
import (
"context"
"go.mongodb.org/mongo-driver/bson/primitive"
"github.com/sv-tools/mongoifc"
)
const (
UsersCollection = "users"
)
type User struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Name string `json:"name,omitempty" bson:"name,omitempty"`
Email string `json:"email,omitempty" bson:"email,omitempty"`
Active bool `json:"active,omitempty" bson:"active,omitempty"`
IsAdmin bool `json:"is_admin,omitempty" bson:"is_admin,omitempty"`
}
func GetAdmins(ctx context.Context, db mongoifc.Database) ([]*User, error) {
var users []*User
cur, err := db.Collection(UsersCollection).Find(ctx, User{
Active: true,
IsAdmin: true,
})
if err != nil {
return nil, err
}
if err := cur.Decode(&users); err != nil {
return nil, err
}
return users, err
} and here is the test, actually two tests. First test uses package simple
import (
"context"
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
gomockMocks "github.com/sv-tools/mongoifc/mocks/gomock"
mockeryMocks "github.com/sv-tools/mongoifc/mocks/mockery"
)
func TestGetAdmins(t *testing.T) {
expectedUsers := []*User{
{Name: "foo", Active: true, IsAdmin: true},
{Name: "bar", Active: true, IsAdmin: true},
}
ctx := context.Background()
t.Run("mockery", func(t *testing.T) {
cur := &mockeryMocks.Cursor{}
cur.On("Decode", mock.Anything).Run(func(args mock.Arguments) {
users := args[0].(*[]*User)
*users = append(*users, expectedUsers...)
}).Return(nil)
col := &mockeryMocks.Collection{}
col.On("Find", ctx, mock.AnythingOfType("User")).Return(cur, nil)
db := &mockeryMocks.Database{}
db.On("Collection", UsersCollection).Return(col)
users, err := GetAdmins(ctx, db)
require.NoError(t, err)
require.Equal(t, expectedUsers, users)
})
t.Run("gomock", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
cur := gomockMocks.NewMockCursor(ctrl)
cur.EXPECT().Decode(gomock.Any()).Do(func(arg interface{}) {
users := arg.(*[]*User)
*users = append(*users, expectedUsers...)
}).Return(nil)
col := gomockMocks.NewMockCollection(ctrl)
col.EXPECT().Find(ctx, gomock.Any()).Return(cur, nil)
db := gomockMocks.NewMockDatabase(ctrl)
db.EXPECT().Collection(UsersCollection).Return(col)
users, err := GetAdmins(ctx, db)
require.NoError(t, err)
require.Equal(t, expectedUsers, users)
})
} |
Beta Was this translation helpful? Give feedback.
-
This example can be found here: https://github.com/sv-tools/mongoifc/tree/main/examples/simple |
Beta Was this translation helpful? Give feedback.
OK. Here is an example of how to mock the mongo objects
Let's say we have a function that returns all admin users: