单元测试 mGo

huangapple go评论81阅读模式
英文:

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

huangapple
  • 本文由 发表于 2014年4月9日 00:49:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/22943392.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定