英文:
Unit Testing mGo
问题
我有一个接受 database *mgo.Database
参数的函数。
func myFunc(db *mgo.Database) {
// 使用 db 进行一些操作
}
我想编写一个单元测试,并传入一个模拟的 db 对象,但是我在使用 golang 时遇到了很大的困难。在其他语言中,我可以使用测试框架来创建一个 myMock = createMock("Class to Mock")
,但是在 Go 中,我不确定如何做到这一点。
我浏览了一下 gomock,但不确定这是否是唯一的方法,也不确定如何使用 mockgen
工具与 mgo 一起使用。
我还考虑过编写一个接口,该接口具有与 mgo.Database 相同的所有方法,并传递一个使用该接口的“模拟”对象,然后创建一个使用该接口并将调用传递给 mgo 库的对象(类似于 ORM),但这似乎需要编写很多代码。
英文:
I have a function that accepts a database *mgo.Database
parameter.
func myFunc(db *mgo.Database) {
// does some operations with db
}
I would like to write a unit test and pass in a mocked db object, but I'm having a very difficult time figuring out how to do that with golang. In other languages I could use there testing frameworks to do a myMock = createMock("Class to Mock")
, but with Go I'm not sure how to do this.
I glanced at gomock, but wasn't sure if that is the only way, and wasn't sure how to use the mockgen
tool with mgo.
I also thought maybe to write an interface that has all of the same methods as mgo.Database and pass a "mocked" object that uses the interface, and then create an object that uses the interface and passes calls through to mgo's library (similar to an ORM), but that seems like a lot of coding.
答案1
得分: 6
*mgo.Database是一个指向类型的指针,而不是一个接口,你不能对其进行模拟。
与其他语言类似,你需要提供一定的间接性,这样你就可以在生产环境中提供一个真实的对象,而在测试中提供一个模拟对象。因此,你的第一步是提取出你的"myFunc"使用的接口(调用哪些方法),然后你可以在生产环境中提供*mgo.Database,而在测试中提供一个模拟对象(手动模拟或使用某些模拟框架)。
这本优秀书籍《单元测试的艺术》的免费样章解释了你需要在第52页(第3章“使用存根打破依赖关系”-“3.3 确定如何轻松测试LogAnalyzer”)上进行的步骤:
http://www.manning.com/osherove/SampleChapter3.pdf
鉴于在Go语言中,一个类型只需实现接口的方法即可实现该接口,这甚至比其他语言(如C#)更容易。
所以答案就像你所说的那样:
编写一个具有与mgo.Database相同的所有方法的接口
传递一个使用该接口的“模拟”对象,然后创建一个使用该接口的对象,并将调用传递给mgo的库(类似于ORM),但这似乎需要大量的编码。
除了你不需要创建一个使用接口并将调用传递给mgo库的对象(类似于ORM)
,因为*mgo.Database将隐式满足你的接口。所以这并不需要太多的编码工作。
英文:
*mgo.Database is a pointer to a type, not an interface, you can't mock it.
As in other languages - you need to provide a level of indirection, so that you can provide a real object in production but a mock for testing. So your first step is to extract the interface that your "myFunc" uses (which methods it calls), then you can provide *mgo.Database in production and your mock (manual mock or using some mocking framework) for testing.
This free sample chapter from great book "The Art of Unit Testing" explains the steps you need to do on page 52 (chapter 3, "Using stubs to break dependencies" - "3.3 Determining how to easily test LogAnalyzer"):
http://www.manning.com/osherove/SampleChapter3.pdf
given that in Go a type implements the interface just by implementing the interface's methods - it's even easier than in other languages (like C# for example)
so the answer is as you said
> to write an interface that has all of the same methods as mgo.Database
> and pass a "mocked" object that uses the interface, and then create an
> object that uses the interface and passes calls through to mgo's
> library (similar to an ORM), but that seems like a lot of coding.
except that you don't need to create an object that uses the interface and passes calls through to mgo's library (similar to an ORM)
because *mgo.Database will implicitly satisfy your interface. So it's not a lot of coding.
答案2
得分: -3
你也可以在单元测试中使用Docker。
我创建了一个帮助进行这种测试的库:https://github.com/skarllot/raiqub
示例:https://github.com/raiqub/data/blob/v0.4/mongostore/store_test.go
英文:
You can use Docker on your unit testing too.
I've created a library to help this kind of testing: https://github.com/skarllot/raiqub
Example: https://github.com/raiqub/data/blob/v0.4/mongostore/store_test.go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论