是否可以在golang中模拟从包中导入的函数?

Pra*_*eep 17 testing unit-testing mocking go

我有以下测试方法,它使用从包导入的函数.

import x.y.z

func abc() {
    ...
    v := z.SomeFunc()
    ... 
}
Run Code Online (Sandbox Code Playgroud)

是否有可能SomeFunc()在golang中嘲笑?

icz*_*cza 27

是的,通过简单的重构.创建一个zSomeFunc函数类型的变量,初始化为z.SomeFunc,并让您的包调用而不是z.SomeFunc():

var zSomeFunc = z.SomeFunc

func abc() {
    // ...
    v := zSomeFunc()
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在测试中,您可以指定另一个函数zSomeFunc,一个在测试中定义,并执行测试所需的任何函数.

例如:

func TestAbc(t *testing.T) {
    // Save current function and restore at the end:
    old := zSomeFunc
    defer func() { zSomeFunc = old }()

    zSomeFunc = func() int {
        // This will be called, do whatever you want to,
        // return whatever you want to
        return 1
    }

    // Call the tested function
    abc()

    // Check expected behavior
}
Run Code Online (Sandbox Code Playgroud)

请参阅相关/可能重复: 使用覆盖率信息测试Go中的os.Exit场景(coveralls.io/Goveralls)

  • 这本质上是全局状态。可能适用于一些微不足道的事情,但也可能会给继承此类代码的人带来严重的痛苦(即几个小时的调试损失)。在专业环境中这不是一个好的模式。 (9认同)
  • 上周我不得不调试一个类似的案例。该测试在与所有其他测试一起运行时失败,但在单独运行时通过。全局状态是指全局可用并且可以更改(已被其他测试更改)的任何变量或符号,包括 func-vars。这实际上是全局状态的定义。 (2认同)

mko*_*iva 7

你可以做的一件事是:

import x.y.z

var someFunc = z.SomeFunc

func abc() {
    ...
    v := someFunc
    ... 
}
Run Code Online (Sandbox Code Playgroud)

在你的测试文件中你会这样做.

func Test_abc() {
    someFunc = mockFunc
    abc()
}
Run Code Online (Sandbox Code Playgroud)

但请确保以并发方式执行此操作,如果您有多个TestXxx函数调用abc或设置someFunc,则可能更适合使用structsomeFunc字段的字符.


小智 5

让函数指针和猴子修补它是其中之一。但是,当您模拟多个函数时,您将拥有多个函数指针,并且不必要地仅使用函数指针来调用函数。

拥有一个接口并使您的功能成为实现该接口的结构的一部分的更好和推荐的想法。完成后,您可以使用一些可用于 go 的不错的工具生成模拟。

我一直在使用这个:

mockgen -source myModule.go -package myPackage -destination myModuleMock.go
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式安装它:

go get github.com/golang/mock
Run Code Online (Sandbox Code Playgroud)