据我所知,如果代码的结构使得它被编程为接口,那么嘲笑它是微不足道的;但是,我正在使用一个我无法改变的代码库(这不是我的代码库),事实并非如此。
这个代码库是高度互联的,没有任何东西被编程到接口,只有结构,所以没有依赖注入。
结构本身只包含其他结构,所以我也不能用这种方式嘲笑。我不相信我可以对方法做任何事情,而且存在的少数函数不是变量,所以我不知道将它们交换掉。继承在golang中不是一件好事,所以这也不行。
在像python这样的脚本语言中,我们可以在运行时修改对象,也就是猴子补丁。在golang中我能做些什么吗?试图找出一些测试/基准测试方法而不触及底层代码。
答案 0 :(得分:4)
当我遇到这种情况时,我的方法是使用我自己的接口作为包装,允许在测试中进行模拟。例如。
type MyInterface interface {
DoSomething(i int) error
DoSomethingElse() ([]int, error)
}
type Concrete struct {
client *somepackage.Client
}
func (c *Concrete) DoSomething(i int) error {
return c.client.DoSomething(i)
}
func (c *Concrete) DoSomethingElse() ([]int, error) {
return c.client.DoSomethingElse()
}
现在你可以像模仿somepackage.Client
一样模拟混凝土,如果它也是一个界面的话。
正如@elithrar在下面的评论中指出的那样,您可以嵌入要模拟的类型,这样您就只能添加需要模拟的方法。例如:
type Concrete struct {
*somepackage.Client
}
如果这样完成,可以直接在DoSomethingNotNeedingMocking
上调用Concrete
等其他方法,而无需将其添加到界面/模拟出来。
答案 1 :(得分:1)
Go有一个available monkey patching library。它仅适用于Intel / AMD系统(特别针对OSX和Ubuntu)。
答案 2 :(得分:1)
根据具体情况,您可以应用“依赖性倒置原则”并利用Go的隐式接口。
为此,您需要在包中定义需求的接口和用法(而不是定义您在实现它的包中提供的内容;就像您在Java中一样)。
然后,您可以独立于依赖项测试代码。
具有struct依赖关系的典型对象:
// Object that relies on a struct
type ObjectUnderTestBefore struct {
db *sql.DB
}
func (o *ObjectUnderTestBefore) Delete() error {
o.db.Exec("DELETE FROM sometable")
}
应用依赖性倒置原则(带隐式接口)
// subset of sql.DB which defines our "requirements"
type dbExec interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}
// Same object with it's requirement defined as an local interface
type ObjectUnderTestWithDIP struct {
// *sql.DB will implicitly implement this interface
db dbExec
}
func (o *ObjectUnderTestWithDIP) Delete() error {
o.db.Exec("DELETE FROM sometable")
}