$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

GolangのHTTP Middlewareをテストする

ほぼ https://medium.com/@PurdonKyle/unit-testing-golang-http-middleware-c7727ca896ea のまんまだけど、自分用にメモ。

GolangのHTTP Middlewareというのは Goで始めるMiddleware - Qiita に紹介されているようなもの。PerlだとPlack Middleware、RubyだとRack Middlewareと概念的には同じだと思う。

HTTP Middlewareを作った時、もちろんMiddlewareもテストをしたい。

テストしたいHTTP Middleware

例えば以下のようなセキュリティ的に重要なヘッダを自動で入れてくれるHTTP Middlewareを考える。

func headerMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("X-XSS-Protection", "1; mode=block")
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("X-Frame-Options", "DENY")
		next.ServeHTTP(w, r)
	})
}

どうテストするか

何もしないhttp.HandlerFuncをHTTP Middlewareに渡して、それをhttptest.NewServerに渡してテストサーバを立ち上げることでテストできる。

こんな感じ。簡単ですね。

// getTestHandler returns a http.HandlerFunc for testing http middleware
func getTestHandler() http.HandlerFunc {
	fn := func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Test Handler")
	}
	return http.HandlerFunc(fn)
}

func TestHeaderMiddleware(t *testing.T) {
	ts := httptest.NewServer(headerMiddleware(getTestHandler()))
	defer ts.Close()

	resp, err := http.Get(ts.URL)
	assert.NoError(t, err)
	defer resp.Body.Close()

	assert.Equal(t, "1; mode=block", resp.Header.Get("X-XSS-Protection"))
	assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options"))
	assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options"))
}

まとめ

今回はGolangのHTTP Middlewareをテストする方法を書いてみた。実際のサンプルコードはここに置いてあります。