Skip to content

Instantly share code, notes, and snippets.

@p4tin
Created July 12, 2018 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p4tin/061c3331e8235446188488780595d9a8 to your computer and use it in GitHub Desktop.
Save p4tin/061c3331e8235446188488780595d9a8 to your computer and use it in GitHub Desktop.
Mocking Mongo
package clients
import (
"github.com/globalsign/mgo"
"testapp"
)
// NewSession returns a new Mongo Session.
func NewSession() testapp.Session {
mgoSession, err := mgo.Dial("localhost:27017")
if err != nil {
panic(err)
}
return MongoSession{mgoSession}
}
// MongoSession is currently a Mongo session.
type MongoSession struct {
*mgo.Session
}
// DB shadows *mgo.DB to returns a DataLayer interface instead of *mgo.Database.
func (s MongoSession) DB(name string) testapp.DataLayer {
return &MongoDatabase{Database: s.Session.DB(name)}
}
// MongoCollection wraps a mgo.Collection to embed methods in models.
type MongoCollection struct {
*mgo.Collection
}
func (m MongoCollection) Find(query interface{}) testapp.Query {
return &MongoQuery{
Query: m.Collection.Find(query),
}
}
// MongoDatabase wraps a mgo.Database to embed methods in models.
type MongoDatabase struct {
*mgo.Database
}
// C shadows *mgo.DB to returns a DataLayer interface instead of *mgo.Database.
func (d MongoDatabase) C(name string) testapp.Collection {
return MongoCollection{Collection: d.Database.C(name)}
}
type MongoQuery struct {
*mgo.Query
}
func (q MongoQuery) Apply(change mgo.Change, result interface{}) (info *mgo.ChangeInfo, err error) {
return q.Query.Apply(change,result)
}
package main
import (
"testapp"
"fmt"
"testapp/clients"
"github.com/pkg/errors"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
)
var (
session testapp.Session
collection testapp.Collection
)
func init() {
session = clients.NewSession()
collection = session.DB("CheckoutService").C("order_numbers")
}
func GetNextNumber() (int, string, error) {
doc := bson.M{}
change := mgo.Change{
Update: bson.M{"$inc": bson.M{"NextId": 1}},
ReturnNew: true,
}
query := collection.Find(bson.M{"siteId": "fp-us"})
_, err := query.Apply(change, &doc)
if err != nil {
return -1, "", errors.New("Could not get an ID from Mongo")
}
return doc["NextId"].(int), doc["prefix"].(string), nil
}
func main() {
num, prefix, err := GetNextNumber()
if err != nil {
panic(err)
}
fmt.Printf("%s%08d\n", prefix, num)
}
package main
import (
"testing"
"testapp/mocks"
)
func Test_GetNextNumber(t *testing.T) {
session = mocks.NewMockSession()
collection = session.DB("CheckoutService").C("order_numbers")
num, prefix, err := GetNextNumber()
if prefix != "FX" {
t.Errorf("Error: %s\n", err.Error())
}
if num != 9999 {
t.Errorf("Error: %d", num)
}
}
package testapp
import "github.com/globalsign/mgo"
// Session is an interface to access to the Session struct.
type Session interface {
DB(name string) DataLayer
Close()
}
// DataLayer is an interface to access to the database struct.
type DataLayer interface {
C(name string) Collection
}
// Collection is an interface to access to the collection struct.
type Collection interface {
Find(query interface{}) Query
}
// Query is an interface to access to the Query struct.
type Query interface {
Apply(change mgo.Change, result interface{}) (info *mgo.ChangeInfo, err error)
}
package mocks
import (
"testapp"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
)
// MockSession satisfies Session and act as a mock of *mgo.session.
type MockSession struct{}
// NewMockSession mock NewSession.
func NewMockSession() testapp.Session {
return MockSession{}
}
// Close mocks mgo.Session.Close().
func (fs MockSession) Close() {}
// DB mocks mgo.Session.DB().
func (fs MockSession) DB(name string) testapp.DataLayer {
mockDatabase := MockDatabase{}
return mockDatabase
}
// MockDatabase satisfies DataLayer and act as a mock.
type MockDatabase struct{}
// MockCollection satisfies Collection and act as a mock.
type MockCollection struct{}
// Find mock.
func (fc MockCollection) Find(query interface{}) testapp.Query {
return MockQuery{}
}
// C mocks mgo.Database(name).Collection(name).
func (db MockDatabase) C(name string) testapp.Collection {
mockCollection := MockCollection{}
return mockCollection
}
type MockQuery struct{}
var ApplyResult = map[string]interface{} {
"siteId": "fp-us",
"NextId": 9999,
"prefix": "FX",
}
func (mq MockQuery) Apply(change mgo.Change, result interface{}) (info *mgo.ChangeInfo, err error) {
*result.(*bson.M) = ApplyResult
return &mgo.ChangeInfo{}, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment