在Go中模拟接收器功能

时间:2015-03-25 02:06:48

标签: unit-testing go mocking

我试图对接收器函数进行单元测试,该函数调用该结构中的其他接收函数。

让我们说我想测试Three()并在下面模拟对two()的调用:

type MyStruct struct {
    a string
    b string
}

func (m *MyStruct) one() int {
    return 2
}

func (m *MyStruct) two() int {
    return m.one() * 2
}

func (m *MyStruct) Three() int {
    return m.two() * 2
}

我正在关注以下answer中的方法二。

我为每个我想要单元测试的函数创建了一个自定义构造函数,并使用模拟版本覆盖这些方法。但我认为,一旦函数数量增加,维护代码可能并不容易。

有没有嘲笑这些功能的首选方法?我希望官方文档有关于如何在不同场景中模拟事物的一些指导,类似于Python提供的mox。

另外,请注意,我不想使用第三方模拟库。

2 个答案:

答案 0 :(得分:4)

这是一种非常惯用的方法来测试你的东西。 其他语言可能需要所有这些嘲弄,但是 请不要在Go中这样做。

在您给出的示例中测试代码的自然方式 将是:1)为MyStruct.one写一个表格驱动的测试 并确保您测试所有情况。现在你知道了one 完美无缺2)对MyStruct.two做同样的事情。 请注意,测试未导出的内容是可行的,有用的 在Go中很常见。现在不再需要嘲笑了 一些方法,只需3)写一些表驱动测试 MyStruct.Three并检查它是否有效。

但也许你的方法onetwo做得更漂亮,而且 访问环境(文件系统,数据库,网络)和 您不希望Three的测试依赖于此吗? 所以重构你的代码吧!也许Three不应该是一种方法 MyStruct但是一个interface OneAndTwoer的函数 作为参数,您的生产代码使用“真实”调用Three 当您的测试代码使用InMemoryMyStrcuts调用它时,MyStructs 哪些不依赖环境?你可以称之为 mock,我称之为接口的不同实现。

在您的示例中,提供建议很简单:使用表驱动 测试onetwoThree,不要嘲笑。 对于更现实的问题,建议可能会有所不同,但是 如果不知道,很难给出一般性建议 情况。最好的一般建议是:看一下测试 标准库,你几乎可以找到有用的模式 每个测试场景。

答案 1 :(得分:0)

您可以进行重构,以在Three中将两个作为函数进行传递,以便您可以直接模拟输入。

func main() {
    var ms MyStruct
    fmt.Println(ms.one())
    fmt.Println(ms.two())
    fmt.Println(ms.Three(ms.two))
}

type MyStruct struct {}

func (m *MyStruct) one() int {
    return 2
}

func (m *MyStruct) two() int {
    return m.one() * 2
}

func (m *MyStruct) Three(two func() int) int {
    return two() * 2
}
相关问题