Golang 测试模拟函数最佳实践

Cia*_*404 3 testing go

我正在为我的代码开发一些测试(使用testing包),我想知道在测试函数中模拟函数的最佳方法是什么:

我应该将函数作为参数传递吗?在这种情况下,如果该函数调用另一个函数呢?我应该将第一个和第二个函数作为测试函数中的参数传递吗?

注意:一些函数在对象上调用(即 someObj.Create())并使用 HTTP API 调用。

更新澄清:

示例:函数

func f1() error {
  ... //some API call
}

func (s *SomeStruct) f2() error {
  return f1
}

func f3() error {
  return nil
}

func f4() error {
  ...
  err = obj.f2()
  ...
  err = f3()
  ...
}
Run Code Online (Sandbox Code Playgroud)

对于上述内容:如果我想测试 f4,模拟 f2 和 f3 的最佳方法是什么?

如果我将 f2 和 f3 作为参数传递给 f4 它将起作用,但是 f2 测试呢?我应该将 f1 作为参数传递给 f2 吗?

如果是这样,那么 f4 的参数中也应该有 f1 吗?

Wil*_*l C 5

作为一般准则,函数不是很容易模拟,因此模拟实现特定接口的结构最符合我们的利益,这些接口可以传递给函数以测试不同的代码分支。请参阅下面的基本示例。

package a

type DoSomethingInterface interface {
    DoSomething() error
}


func DoSomething(a DoSomethingInterface) {
    if err := a.DoSomething(); err != nil {
        fmt.Println("error occurred")
        return
    }
    fmt.Println("no error occurred")
    return
}

package a_test

import (
    "testing"
    "<path to a>/a"
)

type simpleMock struct {
    err error
}

func (m *simpleMock) DoSomething() error {
    return m.err
}

func TestDoSomething(t *testing.T) {
    errorMock := &simpleMock{errors.New("some error")}
    a.DoSomething(errorMock)
    // test that "an error occurred" is logged

    regularMock := &simpleMock{}
    a.DoSomething(regularMock)
    // test "no error occurred" is logged
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,您将测试DoSomething函数和发生的分支,例如。您将为一个测试用例创建一个带有错误的模拟实例,并创建另一个没有错误的模拟实例来测试另一个用例。各自的情况是测试某个字符串是否已经被记录到标准输出;在这种情况下,它将是"error occurred"simpleMock实例化"no error occurred"时出现错误,何时simpleMock未实例化时出现错误。

这当然可以扩展到其他情况,例如。该DoSomething函数实际上返回某种值,并且您希望assertion对该值进行处理。

编辑:

我更新了代码,担心接口存在于另一个包中。请注意,新的更新代码有一个a包含接口和被测功能的包a_test,以及一个仅作为如何进行测试的模板的包a.DoSomething