[インデックス 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言語のテストに関する一般的なプラクティス