为了账号安全,请及时绑定邮箱和手机立即绑定

为超时的单元测试创​​建 deadlineExceededError:true

为超时的单元测试创​​建 deadlineExceededError:true

Go
慕村225694 2023-03-15 15:23:58
我正在尝试在我的项目中创建一个单元测试,我在其中模拟 http 客户端并设置客户端必须返回的响应。我需要这样的行为,因为如果 http 客户端因超时而失败,我的代码需要相应的行为:因此我需要模拟 http 客户端以返回 deadlineExceededError 并对其进行单元测试。到目前为止我尝试的是以client.Do返回的方式模拟客户端 Do 函数:GetDoFunc = func(*http.Request) (*http.Response, error) {    return nil, &url.Error{        Op:  "Post",        Err: context.DeadlineExceeded,    }}它有效但不完全,这意味着当我以这种模拟行为执行代码时,返回的错误类型是:error(*net/url.Error) *{Op: "Post", URL: "", Err: error(context.deadlineExceededError) {}}这又是正确的,但不完全正确。为什么?因为如果我运行代码并且发生真正的超时,我会得到更完整的东西:error(*net/url.Error) *{Op: "Post", URL: "http://localhost:4500/scan/", Err: error(*net/http.httpError) *{err: "context deadline exceeded (Client.Timeout exceeded while awaiting headers)", timeout: true}}我最感兴趣的是timeout: true。如果我设法告诉我的模拟返回它,我可以断言,我发现它比仅断言返回的错误是deadlineExceededError类型更完整。
查看完整描述

1 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

为了不让测试过于复杂,我建议您采用这种方法。首先,首先定义您的错误:


type timeoutError struct {

    err     string

    timeout bool

}


func (e *timeoutError) Error() string {

    return e.err

}


func (e *timeoutError) Timeout() bool {

    return e.timeout

}

这样,timeoutError同时实现了Error()和Timeout接口。

然后你必须为 HTTP 客户端定义模拟:


type mockClient struct{}


func (m *mockClient) Do(req *http.Request) (*http.Response, error) {

    return nil, &timeoutError{

        err:     "context deadline exceeded (Client.Timeout exceeded while awaiting headers)",

        timeout: true,

    }

}

这只是返回上面定义的错误并nil作为 http.Response。最后,让我们看看如何编写示例单元测试:


func TestSlowServer(t *testing.T) {

    r := httptest.NewRequest(http.MethodGet, "http://example.com", nil)

    client := &mockClient{}


    _, err := client.Do(r)


    fmt.Println(err.Error())

}

如果您调试此测试并在变量上使用调试器暂停err,您将看到想要的结果。

由于这种方法,您可以在不增加任何额外复杂性的情况下实现所需的功能。让我知道是否适合你!


查看完整回答
反对 回复 2023-03-15
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信