如何Mock ioUtils.ReadAll读取HTTP响应体时失败(不使用httptest)
解决方案
问题根源
你之前的写法没法触发读取错误,因为bytes.NewBufferString("")的Read方法只会返回0, io.EOF,而ioutil.ReadAll碰到EOF会正常结束,不会抛出错误。哪怕设置了ContentLength:1,也只是读取到的内容长度和声明的不一致,但这不会触发ReadAll的错误,你的业务代码里也没做这个校验,所以走不到错误分支。
正确的Mock实现
要触发读取响应体的错误,得自定义一个能返回错误的io.ReadCloser:
// 自定义一个会返回错误的ReadCloser type errorReader struct{} func (e *errorReader) Read(p []byte) (n int, err error) { return 0, fmt.Errorf("模拟读取响应体失败") } func (e *errorReader) Close() error { return nil }
然后在Mock的Do方法里返回带这个错误Reader的响应:
response := http.Response{ Body: &errorReader{}, // ContentLength不影响,关键是Read方法要返回错误 }
这样业务代码调用ioutil.ReadAll(res.Body)时,就会触发你要的错误分支。
进阶场景:部分读取后报错
如果想模拟读取了一部分内容再报错的情况,也可以修改errorReader的Read方法:
func (e *errorReader) Read(p []byte) (n int, err error) { // 先返回1个字节的内容,再抛出错误 if len(p) > 0 { p[0] = 'x' return 1, fmt.Errorf("模拟读取到部分内容后失败") } return 0, fmt.Errorf("模拟读取响应体失败") }
这样ReadAll会先读到1个字节,再返回错误,同样会进入你的错误处理逻辑。
内容的提问来源于stack exchange,提问作者Tarta
相关产品推荐
相关产品推荐

