[インデックス 11738] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http/httptest パッケージにテストケースを追加するものです。具体的には、httptest.NewServer の基本的な機能を確認するためのテストが server_test.go に追加されています。
コミット
commit ce57ba9feec078191db2873017bd63f996afd835
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Thu Feb 9 16:45:24 2012 +1100
net/http/httptest: add a test
Less ironic. Don't you think?
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5643069
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ce57ba9feec078191db2873017bd63f996afd835
元コミット内容
--- a/src/pkg/net/http/httptest/server_test.go
+++ b/src/pkg/net/http/httptest/server_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httptest
+
+import (
+ "io/ioutil"
+ "net/http"
+ "testing"
+)
+
+func TestServer(t *testing.T) {
+ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("hello"))
+ }))
+ defer ts.Close()
+ res, err := http.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ got, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != "hello" {
+ t.Errorf("got %q, want hello", string(got))
+ }
+}
変更の背景
このコミットは、Go言語の net/http/httptest パッケージにテストを追加するものです。httptest パッケージは、HTTPサーバーやクライアントのテストを容易にするためのユーティリティを提供します。特に httptest.NewServer は、実際のHTTPサーバーを起動せずに、テスト用のHTTPサーバーをメモリ上に構築し、そのURLを提供することで、HTTPハンドラやクライアントの動作を検証できるようにします。
コミットメッセージの "Less ironic. Don't you think?" (皮肉が少ない。そう思わない?) という表現は、httptest パッケージ自体がテストを目的としているにもかかわらず、そのパッケージ自身のテストが不足していたことに対する言及であると考えられます。つまり、テストを支援するツールが、それ自身のテストを欠いているという状況を「皮肉」と表現し、その状況を改善するためにテストを追加した、という背景が読み取れます。
Go言語の初期段階では、標準ライブラリの各パッケージが着実に機能追加され、それに伴いテストカバレッジも拡充されていました。このコミットも、net/http/httptest パッケージの堅牢性を高め、将来的な変更に対する安全性を確保するための一環として行われたものと推測されます。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念とHTTPに関する知識が必要です。
-
Go言語のテストフレームワーク (
testingパッケージ):- Go言語には、標準で
testingパッケージが用意されており、これを使ってユニットテストやベンチマークテストを記述します。 - テスト関数は
TestXxx(*testing.T)の形式で定義され、go testコマンドで実行されます。 *testing.Tオブジェクトは、テストの失敗を報告したり、ログを出力したりするためのメソッド(例:t.Fatal(),t.Errorf())を提供します。deferキーワードは、関数の実行が終了する直前に指定された関数を呼び出すために使用されます。これはリソースのクリーンアップ(例: ファイルのクローズ、サーバーのシャットダウン)によく使われます。
- Go言語には、標準で
-
HTTPハンドラ (
http.Handlerインターフェースとhttp.HandlerFunc):- Go言語の
net/httpパッケージでは、HTTPリクエストを処理するロジックをhttp.Handlerインターフェースとして定義します。このインターフェースはServeHTTP(ResponseWriter, *Request)メソッドを一つだけ持ちます。 http.HandlerFuncは、関数をhttp.Handlerインターフェースに適合させるためのアダプターです。これにより、通常の関数をHTTPハンドラとして使用できるようになります。http.ResponseWriterは、HTTPレスポンスをクライアントに書き込むためのインターフェースです。*http.Requestは、クライアントからのHTTPリクエストに関する情報(URL、ヘッダー、ボディなど)を保持する構造体です。
- Go言語の
-
net/http/httptestパッケージ:- このパッケージは、HTTPサーバーやクライアントのテストを容易にするためのユーティリティを提供します。
httptest.NewServer(handler http.Handler): 指定されたhttp.Handlerを使用して、テスト用のHTTPサーバーを起動します。このサーバーは実際のネットワークポートをリッスンしますが、テストの終了時に自動的にクリーンアップされます。戻り値の*httptest.Serverオブジェクトは、サーバーのURL (ts.URL) やクリーンアップのためのClose()メソッドを提供します。httptest.Server.Close(): テストサーバーをシャットダウンし、リソースを解放します。通常はdeferを使って呼び出されます。
-
io/ioutilパッケージ:ioutil.ReadAll(r io.Reader):io.Readerからすべてのデータを読み込み、[]byteスライスとして返します。HTTPレスポンスボディの読み込みによく使われます。
技術的詳細
このコミットで追加されたテスト TestServer は、net/http/httptest パッケージの NewServer 関数が正しく動作するかどうかを検証します。
テストの基本的な流れは以下の通りです。
-
テストサーバーの起動:
ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello")) }))httptest.NewServerを呼び出してテストサーバーを起動します。- 引数には
http.Handlerインターフェースを実装したオブジェクトを渡す必要があります。ここでは、匿名関数をhttp.HandlerFuncでラップしてハンドラとして使用しています。 - このハンドラは、どのようなリクエストが来ても、レスポンスボディに
"hello"という文字列を書き込むだけのシンプルなものです。 tsは*httptest.Server型のオブジェクトで、テストサーバーに関する情報(例: サーバーのURL)を含んでいます。
-
サーバーのクリーンアップ設定:
defer ts.Close()deferステートメントにより、TestServer関数が終了する際にts.Close()が呼び出され、テストサーバーが適切にシャットダウンされ、使用されたネットワークポートなどのリソースが解放されることを保証します。これにより、テストが完了した後にリソースがリークするのを防ぎます。
-
HTTPリクエストの送信:
res, err := http.Get(ts.URL)http.Get関数を使用して、起動したテストサーバーのURL (ts.URL) に対してGETリクエストを送信します。ts.URLは、httptest.NewServerが内部的に割り当てたランダムなポート番号を含む、テストサーバーの完全なURL文字列です(例:http://127.0.0.1:12345)。- エラーが発生した場合 (
err != nil) は、t.Fatal(err)を呼び出してテストを即座に失敗させます。
-
レスポンスボディの読み込み:
got, err := ioutil.ReadAll(res.Body)http.Getから返された*http.ResponseオブジェクトのBodyフィールド(io.ReadCloser型)から、ioutil.ReadAllを使ってレスポンスボディの内容をすべて読み込みます。- ここでもエラーチェックを行い、エラーがあればテストを失敗させます。
-
結果の検証:
if string(got) != "hello" { t.Errorf("got %q, want hello", string(got)) }- 読み込んだレスポンスボディ (
got) を文字列に変換し、期待される値"hello"と比較します。 - もし一致しない場合は、
t.Errorf()を呼び出してテストの失敗を報告します。t.Errorf()はテストを即座に終了させず、他のテストコードの実行を継続させます。
このテストは、httptest.NewServer が提供するURLにHTTPリクエストを送信し、ハンドラが期待通りにレスポンスを返すことを確認する、非常に基本的なエンドツーエンドテストの例となっています。
コアとなるコードの変更箇所
このコミットでは、src/pkg/net/http/httptest/server_test.go という新しいファイルが追加されています。
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package httptest
import (
"io/ioutil"
"net/http"
"testing"
)
func TestServer(t *testing.T) {
ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
}))
defer ts.Close()
res, err := http.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
got, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if string(got) != "hello" {
t.Errorf("got %q, want hello", string(got))
}
}
コアとなるコードの解説
追加された server_test.go ファイルは、httptest パッケージのテストファイルです。
package httptest: このファイルがhttptestパッケージの一部であることを示します。テストファイルは通常、テスト対象のパッケージと同じパッケージ名を使用します。importステートメント:"io/ioutil": レスポンスボディを読み込むために使用します。"net/http": HTTPクライアント(http.Get)やHTTPハンドラ(http.HandlerFunc)のために使用します。"testing": Go言語のテストフレームワークです。
func TestServer(t *testing.T):- Go言語のテスト関数は
Testで始まり、*testing.T型の引数を取ります。 - この関数内で、
httptest.NewServerを使ってテスト用のHTTPサーバーをセットアップし、そのサーバーに対してHTTPリクエストを送信し、レスポンスを検証する一連の処理が行われます。 t.Fatal(err)は、エラーが発生した場合にテストを即座に終了させ、エラーメッセージを出力します。t.Errorf(...)は、検証が失敗した場合にエラーメッセージを出力しますが、テストの実行は継続します。
- Go言語のテスト関数は
このコードは、httptest.NewServer が提供するテストサーバーが、与えられたハンドラに従ってHTTPリクエストを処理し、期待されるレスポンスを返すことをシンプルかつ効果的に検証しています。
関連リンク
- Go言語の
net/http/httptestパッケージのドキュメント: https://pkg.go.dev/net/http/httptest - Go言語の
net/httpパッケージのドキュメント: https://pkg.go.dev/net/http - Go言語の
testingパッケージのドキュメント: https://pkg.go.dev/testing
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコードリポジトリ (GitHub)
- Go言語のコミット履歴
- 一般的なHTTPプロトコルに関する知識
- Go言語のテストに関する一般的なプラクティス