我正在为我的代码开发一些测试(使用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 吗?
作为一般准则,函数不是很容易模拟,因此模拟实现特定接口的结构最符合我们的利益,这些接口可以传递给函数以测试不同的代码分支。请参阅下面的基本示例。
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。