Goでhttp.ClientのテストをするときにProxyを書き換えてテストサーバにリクエストを投げる

Goで外部リクエストが関わる処理をテストする - Qiitafetch(url string)と違って引数でURLを取れないような関数をテストする場合、
http.DefaultTransport.(*http.Transport).Proxyを書き換えるとテストサーバにリクエストを飛ばせる。

main.go

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func fetch() []byte {
    res, err := http.Get("http://localhost:8000/test")
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }
    return body
}

func main() {
    fmt.Printf("%s", fetch())
}

main_test.go

package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "net/url"
    "testing"
)

func TestFetch(t *testing.T) {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "test")
    }))
    defer ts.Close()

    defaultProxy := http.DefaultTransport.(*http.Transport).Proxy
    http.DefaultTransport.(*http.Transport).Proxy = func(req *http.Request) (*url.URL, error) {
        // テストサーバのURLをProxyに設定
        return url.Parse(ts.URL)
    }
    // テストが終わったらProxyを元に戻す
    defer func() { http.DefaultTransport.(*http.Transport).Proxy = defaultProxy }()

    value := string(fetch())
    expected := "test"
    if value != expected {
        t.Errorf("Expected %v, but %v:", expected, value)
    }
}
参考

mattn.kaoriya.net


前にどこかで似たような記事を見たような気がしたんけど今探したら見つからず...
かわりに

github.com

なんてのがあることを知った。