Golang猴子修补

时间:2016-05-06 18:34:26

标签: go mocking monkeypatching

据我所知,如果代码的结构使得它被编程为接口,那么嘲笑它是微不足道的;但是,我正在使用一个我无法改变的代码库(这不是我的代码库),事实并非如此。

这个代码库是高度互联的,没有任何东西被编程到接口,只有结构,所以没有依赖注入。

结构本身只包含其他结构,所以我也不能用这种方式嘲笑。我不相信我可以对方法做任何事情,而且存在的少数函数不是变量,所以我不知道将它们交换掉。继承在golang中不是一件好事,所以这也不行。

在像python这样的脚本语言中,我们可以在运行时修改对象,也就是猴子补丁。在golang中我能做些什么吗?试图找出一些测试/基准测试方法而不触及底层代码。

3 个答案:

答案 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")
}