dongtuo1482 2017-07-16 07:53
浏览 80
已采纳

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

I'm writing unit tests for http Handlers in golang. When looking at code coverage reports of this I am running into the following issue: When reading the request body from a request, ioutil.ReadAll might return an error that I need to handle. Yet, when I write unit tests for my handler I do not know how to send a request to my handler in a way that it will trigger such an error (premature end of content seems not to generate such an error but will generate an error on unmarshaling the body). This is what I am trying to do:

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...
}

How can I write a test case for HandlePostRequest that also covers the case of bytesErr not being nil?

  • 写回答

1条回答 默认 最新

  • dongtangyi8962 2017-07-16 08:08
    关注

    You may create and use an http.Request forged by you, which deliberately returns an error when reading its body. You don't necessarily need a whole new request, a faulty body is enough (which is an io.ReadCloser).

    Simplest achieved by using the httptest.NewRequest() function where you can pass an io.Reader value which will be used (wrapped to be an io.ReadCloser) as the request body.

    Here's an example io.Reader which deliberately returns an error when attempting to read from it:

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

    Example that will cover your error case:

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

    Output (try it on the Go Playground):

    Error reading the body: test error
    

    See related question if you would need to simulate error reading from a response body (not from a request body): How to force error on reading response body

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用