Mocking 官方 MongoDb 驱动

Vah*_*ari 4 unit-testing mocking go mongodb

我需要定义这些接口来模拟官方 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
}
Run Code Online (Sandbox Code Playgroud)

在 mongo 驱动程序包中有两个结构mongo.Collectionmongo.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
}
Run Code Online (Sandbox Code Playgroud)

struct *mongo.Collection正确实现了MgCollection,所以这段代码编译没有错误

var col mgdriver.MgCollection
col = &mongo.Collection{}
col.FindOne(ctx, nil, nil)
Run Code Online (Sandbox Code Playgroud)

但是 struct *mongo.Database没有实现MgDatabase,所以当我写这样的东西时:

var db mgdriver.MgDatabase
db = &mongo.Database{}
db.Collection("Test", nil)
Run Code Online (Sandbox Code Playgroud)

编译器显示此错误:

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

无论mongo.Collectionmongo.Database在官方包,我不能在包更改任何代码。那么如何更改我的接口以正确模拟官方 mongo 驱动程序?

Mar*_*erg 8

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

type CRUD interface {
  Create(yourModel) error
  Read(page, size, skip) []yourModel
  Update(yourModel) error
  Delete(yourModel) error
}
Run Code Online (Sandbox Code Playgroud)

并实施它。

然后模拟界面,例如使用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
Run Code Online (Sandbox Code Playgroud)

由于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)

}
Run Code Online (Sandbox Code Playgroud)

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

一点点复制比一点点依赖要好。

(不过,请记住给予信用,并保留版权说明。)

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

额外的好处:更换您的实际持久性技术相对容易。