unit-testing - 在 Golang 中测试接受不返回值的回调函数的方法

标签 unit-testing go spy

我正在尝试测试以下功能:

// SendRequestAsync sends request asynchronously, accepts callback
//  func, which it invokes
//
// Parameters:
// - `context` : some context
// - `token` : some token
// - `apiURL` : the URL to hit
// - `callType` : the type of request to make. This should be one of
//  the HTTP verbs (`"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, ...)
// - `callBack` : the func to invoke upon completion
// - `callBackCustomData`: the data to invoke `callBack` with
//
// Since this is an async request, it doesn't return anything.
func (a *APICoreSt) SendRequestAsync(context interface{}, token string, apiURL string, callType APIType, header map[string]string, jsonBody []byte,
    callBack OnCompletion, callBackCustomData interface{}) {
    go func(data interface{}) {
        callBack(a.SendRequest(context, token, apiURL, callType, header, jsonBody), data)
    }(callBackCustomData)
}

其中 OnCompletion 定义为:

type OnCompletion func(result CallResultSt, data interface{})

我的想法立即想到创建一个 spy 回调。为此,我 fork 了 this framework , 想出了以下内容:

// outside the test function
type MySpy struct {
    *spies.Spy
}

func (my *MySpy) Callback(res CallResultSt, data interface{}) {
    my.Called(res, data)
    fmt.Println("Hello world")
    return
}

//in the test function
spy := new(MySpy)

//...some table-driven test logic the generator came up with, containing my data

spy.MatchMethod("Callback", spies.AnyArgs)
assert.NotEmpty(t, spies.CallsTo("Callback"))

它向我打招呼

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    panic: runtime error: invalid memory address or nil pointer dereference

我该如何解决这个问题,并测试这个方法?

最佳答案

我会放弃 spy 的东西。此任务非常简单,您不需要外部依赖项来处理它。您可以改为制作自己的“ spy ”,它有一个 channel ,它在调用函数时将 args 传递到其中。在您的测试中,您然后尝试从 channel 接收。这将强制测试等待回调函数被调用。您还可以考虑添加一个超时期限,这样测试就可以失败,而不是在函数从未被调用时永远阻塞。

// outside the test function
type MySpy struct {
    Args chan MySpyArgs
}

type MySpyArgs struct {
    Res  CallResultSt
    Data interface{}            
}

func (my *MySpy) Callback(res CallResultSt, data interface{}) {
    my.Args <- MySpyArgs{Res: res, Data: data}
}

//in the test function
spyChan := make(chan MySpyArgs)
spy := &MySpy{spyChan}

//...some table-driven test logic the generator came up with, containing my data

args := <-spyChan
// can now assert arguments were as you expected, etc.

一个粗略的工作示例:https://play.golang.org/p/zUYpjXdkz-4 .

如果你想使用超时:

...
select {
case args := <-spyChan:
    // assertions on args
case <-time.After(5 * time.Second):
    // prevent blocking for over 5 seconds and probably fail the test
}

关于unit-testing - 在 Golang 中测试接受不返回值的回调函数的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51880867/

相关文章:

matlab - spy 与颜色 Matlab

javascript - 如何测试事件触发后是否调用了函数?

java - 可以用 Kotlin 编写函数(即在顶层)。我也可以对顶层进行单元测试吗?

unit-testing - 删除错误的播放列表以在 Visual Studio 2012 中测试资源管理器

去 GC 停止我的 goroutine?

pointers - 清除截断指针的更快或更慢的方法?

unit-testing - 我应该如何在 Redux 中对 mapDispatchToProps 进行单元测试?

c# - 模拟 EF 调用时出错

google-app-engine - aetest 和 google.golang.org/appengine

javascript - 如何使用 sinon.js 监视预定义对象