如何测试从请求正文读取时的错误?



我正在为 golang 中的 http 处理程序编写单元测试。在查看此代码覆盖率报告时,我遇到了以下问题:从请求读取请求正文时,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...
}

如何为HandlePostRequest编写一个测试用例,该用例也涵盖了bytesErrnil的情况?

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

最简单的方法是使用httptest.NewRequest()函数,您可以在其中传递一个io.Reader值,该值将用作请求正文(包装为io.ReadCloser(。

下面是一个示例io.Reader它在尝试从中读取时故意返回错误:

type errReader int
func (errReader) Read(p []byte) (n int, err error) {
return 0, errors.New("test error")
}

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

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: %vn", err)
return
}
fmt.Printf("No error, body: %sn", body)
}
func main() {
testRequest := httptest.NewRequest(http.MethodPost, "/something", errReader(0))
HandlePostRequest(nil, testRequest)
}

输出(在Go Playground上尝试(:

Error reading the body: test error

如果需要模拟从响应正文(而不是从请求正文(读取错误,请参阅相关问题:如何在读取响应正文时强制错误

我确实提取了读取正文并处理响应的代码,然后使用以下方法创建了在读取正文时会失败的响应:

package main
import (
"fmt"
"io"
"net/http"
)
type BrokenReader struct{}
func (br *BrokenReader) Read(p []byte) (n int, err error) {
return 0, fmt.Errorf("failed reading")
}
func (br *BrokenReader) Close() error {
return fmt.Errorf("failed closing")
}
func main() {
headers := http.Header{
"Content-Length": {"1"},
}
reader := BrokenReader{}
resp := http.Response{
Body:   &reader,
Header: headers,
}
_, err := io.ReadAll(resp.Body)
fmt.Println(err)
}

https://go.dev/play/p/_R9hI2AWm9G

最新更新