I have a program that calls a web service and I want to write a unit test that checks the correct failure handling (nothing fancy). I use net/http/httptest to simulate the web service (backend). But I haven't figured out so far, how to return a response that fails on the io.ReadAll(res.Body)
.
The simplified code to call the web service is this:
package main
import (
"context"
"io"
"net/http"
)
func apiCall(url string) ([]byte, error) {
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
res, _ := http.DefaultClient.Do(req)
// This is the part I want to check by letting the io.ReadAll fail
resBody, err := io.ReadAll(res.Body)
return resBody, err
}
The unit test looks like this:
package main
import (
"github.com/stretchr/testify/require"
"net/http"
"net/http/httptest"
"testing"
)
func TestIt(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
// How can I make the io.ReadAll(res.Body) return an error?
}))
defer server.Close()
_, err := apiCall(server.URL)
require.Error(t, err)
}
Maybe I am on the wrong track with the httptest. If there is another or better way to test it, just let me know.
Here is also an link to the playground
I'm not sure it is practical enough, because the error situation I made below doesn't occur normally.
But if we focus on only the coverage of the code at the test, we can do it like this.
func TestIt(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Content-Length", "50")
_, _ = w.Write([]byte("a"))
}))
defer server.Close()
_, err := apiCall(server.URL)
require.Error(t, err)
}
Then you get an error at io.ReadAll(res.Body)
at the apiCall
code, saying unexpected EOF
Go playground. https://go.dev/play/p/GLFiozJb_nO
Reference. https://github.com/h2non/gock/issues/75
// ContentLength records the length of the associated content. The
// value -1 indicates that the length is unknown. Unless Request.Method
// is "HEAD", values >= 0 indicate that the given number of bytes may
// be read from Body.
ContentLength int64
The comment says the above. ContentLength
is from the response Content-Length
header. Client expects the 50 bytes of data by ContentLength
but it encounters EOF
right after only a byte. So it returns an error.
If you want to see the deep-side, you can find it sets the Reader
's N
(bytes to read) here. You can follow how it is used by using the debug tool at your IDE.