模拟官方MongoDb驱动程序

8

我需要定义这些接口来模拟官方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.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
}

结构体 *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(string, ...*options.CollectionOptions) *mongo.Collection 需要 Collection(string, ...*options.CollectionOptions) mgdriver.MgCollection mongo.Collectionmongo.Database 都是官方软件包中的内容,我不能更改该软件包中的任何代码。那么如何更改我的接口以正确地模拟官方的 mongo driver?
2个回答

13
通常情况下,你并不需要这样做。你应该定义一个数据访问接口,{{}}。
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格言中的话。
“少依赖一点总比依赖多一点好。”
(记得给出功劳,并保留版权注释。)
因此,使用上述方法,您可以针对模拟快速进行单元测试,获得针对测试量身定制的稳定且可预测的答案,并仅在绝对必要时才对MongoDB进行相对昂贵和缓慢的测试。
额外的好处是:相对容易地替换实际的持久性技术。

正如您所提到的,我为CRUD定义了一个接口,因此我可以在上层模拟CRUD操作。但我的问题是关于编写CRUD操作的测试。我决定使用官方的mongo驱动程序,它不包含类似于dbtest的东西。 - Vahid Jafari
1
@VahidJafari 在你的测试中仍然可以使用 import github.com/globalsign/mgo/dbtest。或者按照建议稍微复制一下。 - Markus W Mahlberg

0

如果有人仍然需要这些接口,我实现了一个简单的包装器来为所有主要类提供接口。请参见GitHub项目

它具有以下对象的接口:

  • 客户端
  • 数据库
  • 会话
  • ChangeStream
  • 游标
  • 集合
  • 单个结果
  • IndexView

主要问题是它需要使用包装器而不是直接对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接