如何在读取响应正文时强制出错

我已经在 go 中编写了 http 客户端包装器,我需要对其进行彻底测试。我正在使用包装器中的 ioutil.ReadAll 读取响应主体。我在弄清楚如何在 httptest 的帮助下强制从响应主体读取失败时遇到了一些麻烦。


package req


func GetContent(url string) ([]byte, error) {

    response, err := httpClient.Get(url)

    // some header validation goes here

    body, err := ioutil.ReadAll(response.Body)

    defer response.Body.Close()


    if err != nil {

        errStr := fmt.Sprintf("Unable to read from body %s", err)

        return nil, errors.New(errStr)

    }


    return body, nil

}

我假设我可以这样设置一个假服务器:


package req_test


func Test_GetContent_RequestBodyReadError(t *testing.T) {


    handler := func(w http.ResponseWriter, r *http.Request) {

        w.WriteHeader(http.StatusOK)

    }


    ts := httptest.NewServer(http.HandlerFunc(handler))

    defer ts.Close()


    _, err := GetContent(ts.URL)


    if err != nil {

        t.Log("Body read failed as expected.")

    } else {

        t.Fatalf("Method did not fail as expected")

    }


}

我假设我需要修改 ResposeWriter。现在,我有什么办法可以修改 responseWriter 从而强制包装器中的 ioutil.ReadAll 失败吗?


我意识到您似乎认为它是这篇文章的副本,虽然您可能会这样认为或可能是,但仅将其标记为重复并不能真正帮助我。在这种情况下,“重复”帖子中答案中提供的代码对我来说意义不大。


不负相思意
浏览 111回答 2
2回答

元芳怎么了

检查 的文档Response.Body以查看何时从中读取可能会返回错误:// Body represents the response body.//// The response body is streamed on demand as the Body field// is read. If the network connection fails or the server// terminates the response, Body.Read calls return an error.//// The http Client and Transport guarantee that Body is always// non-nil, even on responses without a body or responses with// a zero-length body. It is the caller's responsibility to// close Body. The default HTTP client's Transport may not// reuse HTTP/1.x "keep-alive" TCP connections if the Body is// not read to completion and closed.//// The Body is automatically dechunked if the server replied// with a "chunked" Transfer-Encoding.Body io.ReadCloser最简单的方法是从测试处理程序生成无效的 HTTP 响应。怎么做?方法有很多种,一个简单的就是“骗”内容长度:handler := func(w http.ResponseWriter, r *http.Request) {    w.Header().Set("Content-Length", "1")}这个处理程序告诉它有 1 个字节的主体,但实际上它没有发送任何内容。因此在另一端(客户端)尝试从中读取 1 个字节时,显然不会成功,并将导致以下错误:Unable to read from body unexpected EOF

慕后森

要扩展 icza 的精彩答案,您还可以使用httptest.Server对象执行此操作:bodyErrorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {  w.Header().Set("Content-Length", "1")}))defer bodyErrorServer.Close()然后你可以bodyErrorServer.URL像往常一样通过你的测试,你总是会得到一个 EOF 错误:package mainimport (    "bytes"    "fmt"    "io/ioutil"    "net/http"    "net/http/httptest"    "testing"    "time")func getBodyFromURL(service string, clientTimeout int) (string, error) {    var netClient = &http.Client{        Timeout: time.Duration(clientTimeout) * time.Millisecond,    }    rsp, err := netClient.Get(service)    if err != nil {        return "", err    }    defer rsp.Body.Close()    if rsp.StatusCode != 200 {        return "", fmt.Errorf("HTTP request error. Response code: %d", rsp.StatusCode)    }    buf, err := ioutil.ReadAll(rsp.Body)    if err != nil {        return "", err    }    return string(bytes.TrimSpace(buf)), nil}func TestBodyError(t *testing.T) {    bodyErrorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        w.Header().Set("Content-Length", "1")    }))    _, err := getBodyFromURL(bodyErrorServer.URL, 1000)    if err.Error() != "unexpected EOF" {        t.Error("GOT AN ERROR")    } else if err == nil {            t.Error("GOT NO ERROR, THATS WRONG!")    } else {        t.Log("Got an unexpected EOF as expected, horray!")    }}此处的游乐场示例:https ://play.golang.org/p/JzPmatibgZn
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go