はじめに
こんにちは、STORESの高田です。
今回は net/http/httptest
でHTTPクライアントをテストする方法についてご紹介します。
外部サービスのクライアントを含めたテストを実装する際には net/http/httptest
を使うと、外部依存を排除しつつ再現性のあるテストを書くことができます。
基本的な使い方
テストの一例として、 Refresh token を用いて Access token を取得する箇所での使い方を見ていきます。
使い方は以下の通りで、httptest.NewServer
でテスト用のHTTPサーバを作成します。func NewServer(handler http.Handler) *Server
と定義されているので、モックしたい内容を http.Handler interface に沿った形で実装します。以下の例では、refresh_token のプレフィックスが success-refresh-token
である場合に、access_token を含むJSONをレスポンスとして返します。
func Test_GetAccessToken(t *testing.T) { ... server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { fmt.Fprintf(w, "%#v", err) } if r.URL.Path == "/token" { refreshToken := r.Form.Get("refresh_token") if strings.HasPrefix(refreshToken, "success-refresh-token") { res := `{"access_token": "new-access-token-` + refreshToken + `", "expires_in": 3920, "scope": "fooScope", "token_type": "Bearer" }` w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) fmt.Fprint(w, res) } else { fmt.Fprintf(w, "hello") } return } http.NotFound(w, r) })) defer server.Close() ... app.Client.TokenURL = fmt.Sprintf("%s/token", server.URL) // クライアントのリクエスト先をモックサーバに置き換える ... res, err := app.GetAccessToken(ctx, refreshToken) // 通常通り呼び出す(リクエスト先はモックサーバとなる) if err != nil { t.Errorf("GetAccessToken() error = %v", err) } ...
※都合によりコードの抜粋となっています。詳細は httptest package - net/http/httptest - Go Packages をご参照ください。
http.Handler interface を実装すれば良いので、共通のロジックを持つモックサーバを使用したい場合は 以下のように定義して使い回すこともできます。
type testMux struct{} func (p *testMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {...}
また、CI にも乗せやすいので、外部依存のあるテストを書く際には重宝します。
事例として参考にしてもらえればと思います。