doumin1897 2018-08-16 15:44
浏览 386
已采纳

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

I'm trying to test the following function:

// 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)
}

where OnCompletion is defined by:

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

My mind instantly thinks to create a spy callback. To do so, I forked this framework, came up with the following:

// 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"))

and it greeted me with

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

How do I remedy this, and test this method?

  • 写回答

1条回答 默认 最新

  • duannuo7878 2018-08-16 21:23
    关注

    I would ditch the spy stuff. This task is simple enough that you shouldn't need an external dependency to handle it. You could instead make your own "spy" that has a channel it passes args into when the function is called. In your test, you then attempt to receive from the channel. That will force the test to wait for the callback function to be called. You may also consider adding a timeout period so that the test can fail instead of blocking forever if the function is never called.

    // 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.
    

    A crude working example: https://play.golang.org/p/zUYpjXdkz-4.

    And if you want to use a timeout:

    ...
    select {
    case args := <-spyChan:
        // assertions on args
    case <-time.After(5 * time.Second):
        // prevent blocking for over 5 seconds and probably fail the test
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器