[インデックス 1228] ファイルの概要
このコミットは、Go言語の標準ライブラリであるtesting
パッケージ内のexample.go
ファイルに対する変更です。具体的には、テスト実行時に使用されるコマンドラインフラグ-run
と-example
の挙動を調整し、特定のデバッグシナリオにおけるExampleの実行制御を改善することを目的としています。
コミット
commit 28668c3a28c8eee186362692af981d9f4fc4fc96
Author: Rob Pike <r@golang.org>
Date: Mon Feb 27 16:23:22 2012 +1100
cmd/go: run examples even if -run is set if -example is also set
Allows one to disable everything but the example being debugged.
This time for sure.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5700079
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/28668c3a28c8eee186362692af981d9f4fc4fc96
元コミット内容
このコミットは、cmd/go
(go
コマンドの内部実装)がExampleを実行する際のロジックを修正するものです。以前の挙動では、go test
コマンドに-run
フラグが指定されている場合、Exampleは実行されませんでした。この変更により、-run
フラグが指定されていても、同時に-example
フラグも指定されている場合には、Exampleが実行されるようになります。これは、特定のExampleのみをデバッグしたい場合に、他のテストやExampleの実行を抑制しつつ、目的のExampleだけを実行できるようにするための改善です。
変更の背景
Go言語のテストフレームワークでは、go test
コマンドを使用してテスト、ベンチマーク、Exampleを実行します。
-run <regexp>
フラグは、実行するテストやベンチマークの名前を正規表現でフィルタリングするために使用されます。-example <regexp>
フラグは、実行するExampleの名前を正規表現でフィルタリングするために使用されます。
このコミット以前は、-run
フラグが設定されていると、testing
パッケージはExampleの実行を完全にスキップしていました。これは、開発者が特定のテストケースに集中したい場合に、Exampleが意図せず実行されるのを防ぐためのものでした。しかし、この挙動は、特定のExampleをデバッグしたい場合に不便をもたらしました。例えば、go test -run MyTest -example MyExample
のように、特定のテストと特定のExampleを同時に実行したい場合、-run MyTest
が存在するためにMyExample
が実行されないという問題がありました。
このコミットの目的は、この制約を緩和し、開発者が-run
フラグでテストをフィルタリングしつつも、-example
フラグを明示的に指定することで、特定のExampleを強制的に実行できるようにすることです。これにより、デバッグ作業の柔軟性が向上します。コミットメッセージにある「This time for sure.」という表現は、同様の意図を持つ以前の試みがあったことを示唆しており、今回の変更でその問題が確実に解決されることを強調しています。
前提知識の解説
Go言語のtesting
パッケージとExample
Go言語の標準ライブラリには、テスト、ベンチマーク、Exampleを記述するためのtesting
パッケージが含まれています。
- テスト関数:
func TestXxx(*testing.T)
というシグネチャを持つ関数で、コードの正確性を検証します。 - ベンチマーク関数:
func BenchmarkXxx(*testing.B)
というシグネチャを持つ関数で、コードのパフォーマンスを測定します。 - Example関数:
func ExampleXxx()
またはfunc ExampleXxx_Yyy()
というシグネチャを持つ関数で、コードの使用例を示します。Example関数は、その出力がコメントとして記述された期待される出力と一致するかどうかをgo test
コマンドが検証します。これにより、ドキュメントとコードの整合性を保つことができます。Exampleは、パッケージのドキュメントやgodocに自動的に組み込まれるため、コードの利用方法を理解する上で非常に重要です。
go test
コマンドのフラグ
go test
コマンドは、テスト実行を制御するための様々なコマンドラインフラグを提供します。
-run <regexp>
: テスト関数やベンチマーク関数の名前を正規表現でフィルタリングします。指定された正規表現にマッチする名前の関数のみが実行されます。-example <regexp>
: Example関数の名前を正規表現でフィルタリングします。指定された正規表現にマッチする名前のExample関数のみが実行されます。-v
: 詳細なテスト結果を表示します。-bench <regexp>
: ベンチマークを実行し、指定された正規表現にマッチするベンチマーク関数のみを実行します。
*match
と*matchExamples
src/pkg/testing/example.go
のような内部ファイルでは、go test
コマンドのフラグは、flag
パッケージによってパースされ、グローバル変数としてアクセスされます。
*match
:-run
フラグの値に対応するstring
型のポインタ変数です。*matchExamples
:-example
フラグの値に対応するstring
型のポインタ変数です。
これらの変数は、テスト実行ロジック内で、どのテストやExampleを実行すべきかを判断するために使用されます。
技術的詳細
この変更は、src/pkg/testing/example.go
ファイル内のRunExamples
関数にあります。この関数は、GoのテストフレームワークがExampleを実行する際に呼び出される内部関数です。
変更前のコードは以下のようになっていました。
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
if *match != "" {
return // Don't run examples if testing is restricted: we're debugging.
}
ok = true
// ... (Example実行ロジック)
}
このロジックでは、*match
(つまり-run
フラグの値)が空文字列でなければ、即座にreturn
し、Exampleの実行をスキップしていました。これは、「テストが制限されている(-run
が指定されている)場合は、デバッグ中なのでExampleは実行しない」という意図でした。
変更後のコードは以下のようになります。
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
if *match != "" && *matchExamples == "" {
return // Don't run examples if testing is restricted: we're debugging.
}
ok = true
// ... (Example実行ロジック)
}
この変更により、Exampleの実行をスキップする条件が*match != ""
から*match != "" && *matchExamples == ""
に変わりました。
この新しい条件は、以下の論理を意味します。
-run
フラグが設定されている(*match != ""
)- かつ
-example
フラグが設定されていない(*matchExamples == ""
) この両方の条件が真である場合にのみ、Exampleの実行がスキップされます。
したがって、もし-run
フラグが設定されていても、-example
フラグが同時に設定されている場合(つまり*matchExamples != ""
の場合)、*matchExamples == ""
の条件が偽になるため、if
文のブロックは実行されず、RunExamples
関数はExampleの実行ロジックに進むことになります。
この修正は、Goのテストフレームワークがコマンドライン引数をどのように解釈し、テスト実行フローを制御しているかを示す良い例です。特に、複数のフラグが組み合わされた場合の挙動を細かく調整することで、開発者の利便性を高めています。
コアとなるコードの変更箇所
変更はsrc/pkg/testing/example.go
ファイルのRunExamples
関数内の一行です。
--- a/src/pkg/testing/example.go
+++ b/src/pkg/testing/example.go
@@ -23,7 +23,7 @@ type InternalExample struct {
}
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
- if *match != "" {
+ if *match != "" && *matchExamples == "" {
return // Don't run examples if testing is restricted: we're debugging.
}
ok = true
コアとなるコードの解説
変更された行は、RunExamples
関数の冒頭にある条件分岐です。
-
変更前:
if *match != ""
- これは、「もし
-run
フラグが指定されていたら(*match
が空でなければ)、Exampleの実行をスキップする」という意味でした。このロジックは、-run
が指定されている限り、-example
が指定されていてもExampleが実行されないという副作用がありました。
- これは、「もし
-
変更後:
if *match != "" && *matchExamples == ""
- これは、「もし
-run
フラグが指定されていて(*match
が空でなく)、かつ-example
フラグが指定されていない(*matchExamples
が空である)ならば、Exampleの実行をスキップする」という意味になります。 - この新しい条件により、
-run
が指定されていても、-example
が明示的に指定されていれば(例えばgo test -run MyTest -example MyExample
のように)、*matchExamples == ""
の部分が偽となり、if
文のブロックがスキップされ、Exampleが実行されるようになります。 - これにより、開発者は
-run
で他のテストをフィルタリングしつつ、-example
で特定のExampleのみを実行するという、より柔軟なデバッグワークフローを実現できます。
- これは、「もし
この修正は、Goのテストツールが提供するコマンドラインフラグの相互作用を改善し、ユーザーがより細かくテスト実行を制御できるようにするための、小さなしかし重要な変更です。
関連リンク
- Go言語の
testing
パッケージのドキュメント: https://pkg.go.dev/testing go test
コマンドのドキュメント: https://pkg.go.dev/cmd/go#hdr-Test_packages- このコミットのChange-ID (Gerrit): https://golang.org/cl/5700079
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード(
src/pkg/testing/example.go
) - Go言語のIssueトラッカーやGerritのレビューコメント(コミットメッセージに記載されたCLリンクから辿れる情報)
- Go言語のテストに関する一般的な知識