[インデックス 12036] ファイルの概要
このコミットは、Go言語の標準ライブラリにおけるいくつかのテストの実行時間を短縮することを目的としています。具体的には、go test -short
フラグが指定された場合に、時間のかかるテストの一部をスキップまたは短縮する変更が加えられています。これにより、開発者がテストをより迅速に実行できるようになり、開発サイクル全体の効率が向上します。
コミット
commit 0e70f2722b5e30244892dd41877f1770dae25122
Author: Russ Cox <rsc@golang.org>
Date: Sat Feb 18 16:24:23 2012 -0500
all: shorten some of the longer tests
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5675092
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0e70f2722b5e30244892dd41877f1770dae25122
元コミット内容
all: shorten some of the longer tests
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5675092
変更の背景
Go言語のプロジェクトでは、テストの実行時間は開発効率に直結する重要な要素です。特に大規模なプロジェクトやCI/CD環境では、全てのテストを毎回実行すると膨大な時間がかかることがあります。このコミットが作成された2012年当時も、Goの標準ライブラリのテストスイートは成長しており、一部のテストが非常に長い時間を要するようになっていました。
このような背景から、開発者が日常的にテストを実行する際に、より高速なフィードバックを得られるようにするための仕組みが求められていました。go test -short
フラグは、このニーズに応えるために導入されたもので、このコミットはそのフラグに対応するために既存のテストコードを修正し、テストの実行時間を短縮することを目的としています。これにより、開発者はフルテストを実行する前に、主要な機能が壊れていないことを素早く確認できるようになります。
前提知識の解説
Go言語のテストフレームワーク (testing
パッケージ)
Go言語には、標準ライブラリとして testing
パッケージが提供されており、これを用いてユニットテストやベンチマークテストを記述します。テスト関数は TestXxx(*testing.T)
の形式で定義され、go test
コマンドで実行されます。
testing.T
型は、テストの実行中にテストの状態を管理し、エラーを報告するためのメソッドを提供します。このコミットで特に重要なのは、testing.Short()
関数です。
testing.Short()
関数
testing.Short()
は、go test -short
コマンドラインフラグが指定されている場合に true
を返すブール関数です。この関数を使用することで、開発者はテストコード内で、go test -short
が有効になっているかどうかをプログラム的にチェックし、それに応じてテストの動作を変更できます。
一般的な用途としては、以下のようなものがあります。
- 時間のかかるテストのスキップ: ネットワークアクセス、ファイルI/O、計算量の多い処理など、実行に時間がかかるテストを
testing.Short()
がtrue
の場合にスキップする。 - テストのイテレーション回数の削減: ループ回数を減らすなどして、テストの実行時間を短縮する。
- リソース集約型テストの無効化: 外部サービスへの依存や大量のメモリを消費するテストを無効にする。
これにより、開発者は日常的な開発では高速な「ショートテスト」を実行し、CI/CD環境やリリース前の最終確認では全てのテストを実行するといった使い分けが可能になります。
t.Logf()
と t.Skipf()
t.Logf(format string, args ...interface{})
: テスト中にログメッセージを出力します。go test -v
フラグが指定された場合に表示されます。t.Skipf(format string, args ...interface{})
: テストをスキップし、その理由をログに出力します。テストがスキップされた場合でも、テストスイート全体は失敗とはなりません。このコミットでは、t.Logf
を使用してスキップする旨をログに出力していますが、より厳密にはt.Skipf
を使用してテストをスキップすることも可能です。
break
文
Go言語における break
文は、ループ(for
、switch
、select
)の実行を即座に終了するために使用されます。このコミットでは、testing.Short()
が true
の場合に、テストループのイテレーションを途中で打ち切るために使用されています。これにより、テストケースの一部のみが実行され、全体の実行時間が短縮されます。
src/pkg/old/netchan
パッケージ
netchan
パッケージは、Go言語の初期のバージョンに存在した、ネットワーク越しにチャネルを介した通信を可能にする実験的なパッケージでした。しかし、Go言語の進化とともに、より汎用的な net/rpc
や encoding/gob
などのパッケージが提供されるようになり、netchan
は最終的にGo 1.0のリリース前に削除されました。このコミットの時点ではまだ存在していましたが、src/pkg/old/
ディレクトリにあることからも、すでに非推奨または将来的に削除されることが示唆されていました。
技術的詳細
このコミットの技術的な核心は、Goの testing
パッケージが提供する testing.Short()
関数を利用して、テストの実行フローを条件分岐させる点にあります。
変更された各テストファイルでは、主に以下の2つのパターンで testing.Short()
が利用されています。
-
ループ内の
break
:TestDeflateInflateString
(src/pkg/compress/flate/deflate_test.go
)、TestYCbCr
(src/pkg/image/ycbcr_test.go
)、TestStringPowers
(src/pkg/math/big/nat_test.go
)、TestNonStandardNormalValues
(src/pkg/math/rand/rand_test.go
)、TestNonStandardExponentialValues
(src/pkg/math/rand/rand_test.go
) の各テストでは、複数のテストケースをループで回しています。これらのループ内でif testing.Short() { break }
という条件分岐が追加されています。 これは、go test -short
が指定された場合、ループの最初のイテレーション(または特定の条件を満たした最初のイテレーション)でループを中断し、残りのテストケースの実行をスキップすることを意味します。これにより、テストの網羅性は低下しますが、実行時間は大幅に短縮されます。 -
テスト関数の早期リターン:
TestRegression2508
(src/pkg/compress/flate/deflate_test.go
)、TestIndependentSends
(src/pkg/old/netchan/netchan_test.go
)、TestExportFlowControl
(src/pkg/old/netchan/netchan_test.go
)、TestImportFlowControl
(src/pkg/old/netchan/netchan_test.go
) の各テストでは、テスト関数の冒頭でif testing.Short() { t.Logf("test disabled with -short"); return }
またはif testing.Short() { t.Logf("disabled test during -short"); return }
という条件分岐が追加されています。 これは、go test -short
が指定された場合、テスト関数全体を早期に終了させ、そのテストを完全にスキップすることを意味します。これらのテストは、おそらく実行時間が非常に長いか、リソースを多く消費するため、ショートテスト時には実行しない方が効率的であると判断されたと考えられます。
これらの変更により、開発者は go test -short
を実行することで、Go標準ライブラリのテストスイート全体をより迅速に実行できるようになり、日常的な開発における生産性が向上します。
コアとなるコードの変更箇所
このコミットでは、以下の5つのファイルが変更されています。
src/pkg/compress/flate/deflate_test.go
src/pkg/image/ycbcr_test.go
src/pkg/math/big/nat_test.go
src/pkg/math/rand/rand_test.go
src/pkg/old/netchan/netchan_test.go
それぞれのファイルで、testing.Short()
を利用した条件分岐が追加されています。
例1: ループ内の break
(src/pkg/compress/flate/deflate_test.go)
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -306,6 +306,9 @@ func TestDeflateInflateString(t *testing.T) {
t.Error(err)
}
testToFromWithLimit(t, gold, test.label, test.limit)
+ if testing.Short() {
+ break
+ }
}
}
例2: テスト関数の早期リターン (src/pkg/compress/flate/deflate_test.go)
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -363,6 +366,10 @@ func TestWriterDict(t *testing.T) {
// See http://code.google.com/p/go/issues/detail?id=2508
func TestRegression2508(t *testing.T) {
+ if testing.Short() {
+ t.Logf("test disabled with -short")
+ return
+ }
w, err := NewWriter(ioutil.Discard, 1)
if err != nil {
t.Fatalf("NewWriter: %v", err)
コアとなるコードの解説
上記の変更箇所は、Goのテストにおける一般的なパターンを示しています。
ループ内の break
の解説
TestDeflateInflateString
のようなテストでは、for
ループを使って複数の異なる入力や設定で同じテストロジックを繰り返し実行しています。これは、テストの網羅性を高めるための一般的な手法です。
if testing.Short() { break }
という行が追加されることで、go test -short
が実行された場合、ループは最初のイテレーションが完了した直後に中断されます。これにより、テストスイート全体が実行される代わりに、各テストの代表的なケースのみが実行されることになります。例えば、1000個のテストケースがある場合、go test -short
では最初の1つだけが実行され、残りの999個はスキップされます。これは、テストの実行時間を劇的に短縮する効果があります。
テスト関数の早期リターンの解説
TestRegression2508
や TestIndependentSends
のようなテストでは、テスト関数の冒頭で if testing.Short() { ... return }
というガード句が追加されています。
t.Logf("test disabled with -short")
は、テストがスキップされたことをユーザーに通知するためのログメッセージを出力します。return
ステートメントは、現在のテスト関数の実行を即座に終了させます。これにより、go test -short
が指定された場合、これらのテストは全く実行されず、テストスイートの実行時間から完全に除外されます。これは、特に実行に非常に長い時間がかかるテストや、外部リソースへの依存があるテスト(例: ネットワーク通信を伴う netchan
のテスト)に対して有効な戦略です。
これらの変更は、Go言語のテストプラクティスにおいて、開発者の利便性とテストの効率性を両立させるための重要な改善点と言えます。
関連リンク
- Go言語
testing
パッケージのドキュメント: https://pkg.go.dev/testing go test
コマンドのドキュメント: https://pkg.go.dev/cmd/go#hdr-Test_packages- Go issue 2508 (TestRegression2508に関連): https://code.google.com/p/go/issues/detail?id=2508 (現在はGoのIssue TrackerがGitHubに移行しているため、直接アクセスできない可能性がありますが、当時のGoプロジェクトのIssue管理システムでの参照です。)
参考にした情報源リンク
- Go言語の公式ドキュメント (
testing
パッケージ、go test
コマンド) - Go言語のソースコード (特に
src/testing/testing.go
でShort()
関数の実装を確認) - Go言語のコミット履歴と関連するコードレビュー (Gerrit CL 5675092)
netchan
パッケージに関する歴史的情報 (Go言語の進化に関する記事や議論)- 一般的なソフトウェアテストのプラクティスと、テスト実行時間の最適化に関する情報