1

I have a simple function which takes a URL and fetches the response:

func getUrl(url string) (string, error) {
    var theClient = &http.Client{Timeout: 12 * time.Second}

    resp, err := theClient.Get(url)
    if err != nil {
        return "", err
    }
    defer r.Body.Close()

    body, readErr := ioutil.ReadAll(resp.Body)
    if readErr != nil {
        return "", readErr
    }

    return string(body), nil
}

Now, I want to trigger an error on the theClient.Get(url) line but I don't know how to. I can trigger an error on the ReadAll() line, by returning no response but with content-length:2.

How can I trigger an error on the theClient.Get(url) line for my unit test?

func TestGetUrl(t *testing.T) {
    server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Length", "2")
    }))
    defer server.Close()

    gotContent, gotErr := getUrl(server.URL)
    wantErr := "unexpected EOF"

    if gotErr == nil || gotErr.Error() != wantErr {
        t.Errorf("got err %v; wanted %s", gotErr, wantErr)
    }
}
ServerBloke
  • 802
  • 3
  • 15
  • 24
  • Does this answer your question? [Mock functions in Go](https://stackoverflow.com/questions/19167970/mock-functions-in-go) –  Jul 30 '21 at 19:30
  • @mh-cbon unfortunately not. I am looking to trigger an error at the `.Get()` call of my `httptest.NewServer`. I already have a successful test for a good response and a read error. – ServerBloke Jul 30 '21 at 19:40
  • If you can change the get url implementation, you can find a solution from [here](https://stackoverflow.com/questions/43240970/how-to-mock-http-client-do-method) – nipuna Jul 30 '21 at 19:56
  • `I am looking to trigger an error at the .Get() call of my httptest.NewServer` what does it mean ? –  Jul 30 '21 at 20:07
  • just pass a custom http client to the function, make it behave the way you need to trigger the error you want and respond with the body you wish. –  Jul 30 '21 at 20:08
  • 1
    I think that it is worth to consider what @nipuna suggests. The solution with passing invalid URL could lead to a situation when test will stop giving you a proof that you properly handle error from the client. You could in the future start using `httpClient.Do(request)` and instantiate request separately with `request, err := http.NewRequest(...)`. The test will receive an error from call to `http.NewRequest`. And the call to `httpClient.Do` will remain untested. – Jaroslaw Jul 30 '21 at 20:14

1 Answers1

0

Easiest way is to simply pass an invalid URL:

_, err := http.Get("clearly not a valid url")
fmt.Println("Got error:", err != nil) // Got error: true

Another option is to make it timeout by sleeping in your httptest.Server handler, but that doesn't seem like a very nice idea (but you will be able to assert that it was called in the first place).

Emile Pels
  • 3,837
  • 1
  • 15
  • 23