模拟MongoDb官方驱动程序

时间:2019-09-17 04:59:59

标签: mongodb unit-testing go mocking

我需要定义这些接口来模拟正式的mongo驱动程序

type MgCollection interface {   
    FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) *mongo.SingleResult
    // Other methods
}

type MgDatabase interface {
    Collection(name string, opts ...*options.CollectionOptions) MgCollection
    // Other methods
}

在mongo驱动程序包中,有两种使用这些方法的结构 mongo.Collection mongo.Database

func (coll *Collection) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) *SingleResult {
    // Method code
}

func (db *Database) Collection(name string, opts ...*options.CollectionOptions) *Collection {
    // Method code
}

结构 * mongo.Collection 正确实现了 MgCollection ,因此该代码可以正确编译

var col mgdriver.MgCollection
col = &mongo.Collection{}
col.FindOne(ctx, nil, nil)

但是结构 * mongo.Database 无法实现 MgDatabase ,所以我在编写类似这样的内容时:

var db mgdriver.MgDatabase
db = &mongo.Database{}
db.Collection("Test", nil)

编译器显示此错误:

  

不能使用&mongo.Database文字(类型* mongo.Database)作为类型   分配中的mgdriver.MgDatabase:* mongo.Database未实现   mgdriver.MgDatabase(错误的Collection方法类型)具有   Collection(字符串,... * options.CollectionOptions)* mongo.Collection         想要Collection(string,... * options.CollectionOptions)   mgdriver.MgCollection

mongo.Collection mongo.Database 都在官方程序包中,我无法更改该程序包中的任何代码。那么如何更改我的界面以正确模拟官方mongo驱动程序?

1 个答案:

答案 0 :(得分:2)

通常,您不需要。您应该做的是定义一个数据访问接口

type CRUD interface {
  Create(yourModel) error
  Read(page, size, skip) []yourModel
  Update(yourModel) error
  Delete(yourModel) error
}

并实施它。

然后,您可以模拟界面,例如使用testify/mock

type MockedCRUD struct {
  mock.Mock
}

func(m *MockedCRUD)Create(y yourModel) error{
  returned m.Called(y).Error(0)
}
// And so on and so forth

由于MockedCRUD满足CRUD接口,因此您可以像使用MongoCRUD实现那样使用它,而不会遇到任何麻烦:

func TestYourApplicationLogicCallingCreate( t *testing.T){
    model := YourModel{Type: ”Baz”})

    mocked := new(MockedCRUD)
    mocked.On(”Create”,model).Return(ErrInvalidType)

    app := YourApplication{CRUD:mocked}

    err := app.yourApplicationLogicCallingCreate(model)

    assert.Error(t,err)
    assert.Equal(t,ErrInvalidType,err)

}

仍然是一个问题,您如何测试CRUD接口的实现。我曾经使用过最初由Gustavo Niemeyer开发并由globalsign接管的mgo驱动程序。那带来了一个叫做dbtest的漂亮小包装。实际上,它是围绕MongoDB实例的非常薄的包装器,可以按需启动和停止实例,并能够在两次测试之间重置数据。要么导入dbtest,要么引用Go Pro谚语

  

一点点拷贝比一点点依赖要好。

(不过请记住要感谢您,并保留版权说明。)

因此,使用上述方法,您可以对模拟进行相当快速的单元测试,并为测试量身定制稳定且可预测的答案,并且仅在绝对必要时才对MongoDB进行相对昂贵且缓慢的测试。

增加的好处:换出您的实际持久性技术相对容易。