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 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示