如何在请求体读取时测试错误?

m90*_*m90 8 error-handling unit-testing http go

我正在golang中编写http Handlers的单元测试.在查看代码覆盖率报告时,我遇到了以下问题:从请求中读取请求正文时,ioutil.ReadAll可能会返回我需要处理的错误.然而,当我为我的处理程序编写单元测试时,我不知道如何以一种会触发这种错误的方式向我的处理程序发送请求(内容的过早结束似乎不会产生这样的错误但会产生错误解构身体).这就是我想要做的:

package demo

import (
    "bytes"
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"
)

func HandlePostRequest(w http.ResponseWriter, r *http.Request) {
    body, bytesErr := ioutil.ReadAll(r.Body)
    if bytesErr != nil {
        // intricate logic goes here, how can i test it?
        http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
        return
    }
    defer r.Body.Close()
    // continue...
}

func TestHandlePostRequest(t *testing.T) {
    ts := httptest.NewServer(http.HandlerFunc(HandlePostRequest))
    data, _ := ioutil.ReadFile("testdata/fixture.json")
    res, err := http.Post(ts.URL, "application/json", bytes.NewReader(data))
    // continue...
}
Run Code Online (Sandbox Code Playgroud)

如何编写测试用例HandlePostRequest还包括bytesErr不存在的情况nil

icz*_*cza 19

您可以创建并使用http.Request伪造的,在阅读其正文时故意返回错误.你不一定需要一个全新的请求,一个有缺陷的身体就足够了(这是一个io.ReadCloser).

通过使用httptest.NewRequest()函数可以实现最简单的方法,您可以io.Reader将要使用的值(包装为an io.ReadCloser)作为请求体传递.

这是一个io.Reader在尝试读取错误时故意返回错误的示例:

type errReader int

func (errReader) Read(p []byte) (n int, err error) {
    return 0, errors.New("test error")
}
Run Code Online (Sandbox Code Playgroud)

将涵盖您的错误案例的示例:

func HandlePostRequest(w http.ResponseWriter, r *http.Request) {
    defer r.Body.Close()
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        fmt.Printf("Error reading the body: %v\n", err)
        return
    }
    fmt.Printf("No error, body: %s\n", body)
}

func main() {
    testRequest := httptest.NewRequest(http.MethodPost, "/something", errReader(0))
    HandlePostRequest(nil, testRequest)
}
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

Error reading the body: test error
Run Code Online (Sandbox Code Playgroud)