[インデックス 19625] ファイルの概要
このコミットは、Go言語の cmd/go
ツール、特に go test
コマンドの動作に関するものです。具体的には、外部テストパッケージ(_xtest
)内に存在する、実行されない(Output:
コメントを持たない)Example関数を含むファイルが、go test
実行時に適切にビルドされるように修正を行っています。これにより、これらのExample関数に含まれるコードがコンパイル時にチェックされ、潜在的なエラーが早期に発見されるようになります。
コミット
commit ea0fb5d8e2ba795f0fc985da27a9514492abd7bb
Author: Andrew Gerrand <adg@golang.org>
Date: Sat Jun 28 07:15:22 2014 +1000
cmd/go: build non-runnable examples in xtests
Include these files in the build,
even though they don't get executed.
LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/108180043
---
src/cmd/go/test.bash | 8 +++++
src/cmd/go/test.go | 39 +++++++++++++-----------\
src/cmd/go/testdata/norunexample/example_test.go | 11 +++++++
src/cmd/go/testdata/norunexample/test_test.go | 10 ++++++\
4 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 0060ce2185..c62f629405 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -806,6 +806,14 @@ if ! ./testgo test xtestonly >/dev/null; then
fi
unset GOPATH
+TEST 'go test builds an xtest containing only non-runnable examples'
+if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
+\techo "go test ./testdata/norunexample failed"
+\tok=false
+elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
+\techo "file with non-runnable example was not built"
+\tok=false
+fi
# clean up
if $started; then stop; fi
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 5935c98db9..a602469e44 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -723,10 +723,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,\
if err != nil {
return nil, nil, nil, err
}\n-\tif t.NeedTest || ptest.coverMode != "" {\n+\tif t.ImportTest || ptest.coverMode != "" {\n \t\tpmain.imports = append(pmain.imports, ptest)\n \t}\n-\tif t.NeedTest || ptest.coverMode != "" {\n+\tif t.ImportTest || ptest.coverMode != "" {\n \t\tpmain.imports = append(pmain.imports, ptest)\n \t}\n-\tif t.NeedXtest {\n+\tif t.ImportXtest {\n \t\tpmain.imports = append(pmain.imports, pxtest)\n \t}\n \n@@ -1082,12 +1082,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {\n \tPackage: ptest,\n \t}\n for _, file := range ptest.TestGoFiles {\n-\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {\n+\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {\n \t\t\treturn nil, err\n \t\t}\n \t}\n \tfor _, file := range ptest.XTestGoFiles {\n-\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {\n+\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {\n \t\t\treturn nil, err\n \t\t}\n \t}\n@@ -1110,13 +1110,15 @@ func writeTestmain(out string, t *testFuncs) error {\n }\n \n type testFuncs struct {\n-\tTests []testFunc\n-\tBenchmarks []testFunc\n-\tExamples []testFunc\n-\tPackage *Package\n-\tNeedTest bool\n-\tNeedXtest bool\n-\tCover []coverInfo\n+\tTests []testFunc\n+\tBenchmarks []testFunc\n+\tExamples []testFunc\n+\tPackage *Package\n+\tImportTest bool\n+\tNeedTest bool\n+\tImportXtest bool\n+\tNeedXtest bool\n+\tCover []coverInfo\n }\n \n func (t *testFuncs) CoverMode() string {\n@@ -1151,7 +1153,7 @@ type testFunc struct {\n \n var testFileSet = token.NewFileSet()\n \n-func (t *testFuncs) load(filename, pkg string, seen *bool) error {\n+func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {\n \tf, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)\n \tif err != nil {\n \t\treturn expandScanner(err)\n@@ -1168,15 +1170,16 @@ func (t *testFuncs) load(filename, pkg string, seen *bool) error {\n \t\tswitch {\n \t\tcase isTest(name, "Test"):\n \t\t\tt.Tests = append(t.Tests, testFunc{pkg, name, ""})\n-\t\t\t*seen = true\n+\t\t\t*doImport, *seen = true, true\n \t\tcase isTest(name, "Benchmark"):\n \t\t\tt.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})\n-\t\t\t*seen = true\n+\t\t\t*doImport, *seen = true, true\n \t\t}\n \t}\n \tex := doc.Examples(f)\n \tsort.Sort(byOrder(ex))\n \tfor _, e := range ex {\n+\t\t*doImport = true // import test file whether executed or not\n \t\tif e.Output == "" && !e.EmptyOutput {\n \t\t\t// Don't run examples with no output.\n \t\t\tcontinue\n@@ -1200,11 +1203,11 @@ import (\n \t"regexp"\n \t"testing"\n \n-{{if .NeedTest}}\n-\t_test {{.Package.ImportPath | printf "%q"}}\n+{{if .ImportTest}}\n+\t{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}\n {{end}}\n-{{if .NeedXtest}}\n-\t_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}\n+{{if .ImportXtest}}\n+\t{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}\n {{end}}\n {{range $i, $p := .Cover}}\n \t_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}\ndiff --git a/src/cmd/go/testdata/norunexample/example_test.go b/src/cmd/go/testdata/norunexample/example_test.go
new file mode 100644
index 0000000000..e158305a6c
--- /dev/null
+++ b/src/cmd/go/testdata/norunexample/example_test.go
@@ -0,0 +1,11 @@
+package pkg_test
+
+import "os"
+
+func init() {
+\tos.Stdout.Write([]byte("File with non-runnable example was built.\n"))
+}\n+\n+func Example_test() {
+\t// This test will not be run, it has no "Output:" comment.
+}\ndiff --git a/src/cmd/go/testdata/norunexample/test_test.go b/src/cmd/go/testdata/norunexample/test_test.go
new file mode 100644
index 0000000000..d2e919838f
--- /dev/null
+++ b/src/cmd/go/testdata/norunexample/test_test.go
@@ -0,0 +1,10 @@
+package pkg
+
+import (
+\t"os"
+\t"testing"
+)\n+\n+func TestBuilt(t *testing.T) {
+\tos.Stdout.Write([]byte("A normal test was executed.\n"))
+}\n```
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/ea0fb5d8e2ba795f0fc985da27a9514492abd7bb](https://github.com/golang/go/commit/ea0fb5d8e2ba795f0fc985da27a9514492abd7bb)
## 元コミット内容
`cmd/go`: 外部テストパッケージ(`xtests`)内の非実行可能なExample関数をビルドする。
これらのファイルは実行されないにもかかわらず、ビルドに含める。
## 変更の背景
Goの `go test` コマンドは、テスト関数(`TestXxx`)、ベンチマーク関数(`BenchmarkXxx`)、およびExample関数(`ExampleXxx`)を検出して実行します。Example関数は、コードの利用例を示すために使用され、`// Output:` コメントを持つ場合はその出力が検証されます。しかし、`// Output:` コメントを持たないExample関数(非実行可能なExample)は、通常は実行されません。
このコミット以前は、`go test` が外部テストパッケージ(`_xtest`)内の非実行可能なExample関数を含むファイルを適切にビルドしないという問題がありました。これは、これらのExample関数に含まれるコードがコンパイル時にチェックされず、構文エラーや型エラーなどの問題が見過ごされる可能性を意味していました。開発者がExample関数を記述する目的の一つは、そのコードが常に有効であることを保証することでもあるため、ビルドプロセスから除外されることは望ましくありませんでした。
この変更は、非実行可能なExample関数であっても、それが外部テストパッケージに存在する場合に、`go test` がそのファイルをビルドプロセスに含めるようにすることで、この問題を解決することを目的としています。これにより、Example関数が単なるドキュメントとしてだけでなく、コードの健全性を保証する役割も果たすようになります。
## 前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語のテストに関する概念と `go test` コマンドの内部動作に関する知識が必要です。
### `go test` コマンド
`go test` はGo言語の標準的なテスト実行ツールです。指定されたパッケージ内のテストファイル(`_test.go` で終わるファイル)をコンパイルし、テスト関数、ベンチマーク関数、Example関数を実行します。
### `_test.go` ファイル
Goのテストコードは、テスト対象のGoファイルと同じディレクトリに配置され、ファイル名が `_test.go` で終わる必要があります(例: `my_package_test.go`)。これらのファイルは通常のビルドプロセスからは除外されますが、`go test` コマンドが実行される際にコンパイルされ、テストバイナリに含められます。
### 内部テストパッケージ (Internal Test Package)
テストファイルが、テスト対象のパッケージと同じパッケージ名(例: `package mypackage`)を宣言している場合、それは「内部テストパッケージ」と呼ばれます。この場合、テストコードはテスト対象パッケージの非公開(unexported)な識別子(関数、変数、構造体フィールドなど)にも直接アクセスできます。これは、パッケージの内部実装の詳細をテストするユニットテストに適しています。
### 外部テストパッケージ (External Test Package)
テストファイルが、テスト対象のパッケージ名に `_test` サフィックスを付けたパッケージ名(例: `package mypackage_test`)を宣言している場合、それは「外部テストパッケージ」と呼ばれます。この場合、テストコードはテスト対象パッケージを明示的にインポートする必要があります(例: `import "your_module/mypackage"`)。外部テストパッケージは、テスト対象パッケージの公開(exported)な識別子にのみアクセスできます。これは、パッケージを外部の利用者の視点からテストする「ブラックボックステスト」に適しており、パッケージの公開APIと振る舞いに焦点を当てたテストを書く際に推奨されます。このコミットで言及されている `xtests` は、この外部テストパッケージを指します。
### GoのExample関数
Example関数は、`Example` プレフィックスを持つ関数で、`_test.go` ファイル内に記述されます。これらは、パッケージ、関数、型、またはメソッドの利用例を示すために使用されます。
* **実行可能なExample**: Example関数の最後に `// Output: expected output` の形式でコメントが記述されている場合、`go test` はそのExample関数を実行し、標準出力に書き込まれた内容が `expected output` と一致するかどうかを検証します。これにより、ドキュメントとしてのExampleが常に正しく動作することを保証できます。
* **非実行可能なExample**: Example関数に `// Output:` コメントがない場合、`go test` はそのExample関数をコンパイルしますが、実行はしません。これらのExampleは、主にドキュメント目的で使用され、コードの利用方法を示すためのものです。このコミットの焦点は、まさにこの「非実行可能なExample」が `_xtest` に存在する場合のビルド動作にあります。
## 技術的詳細
このコミットの技術的な核心は、`go test` コマンドがテストバイナリを生成する際の、テストパッケージのインポート判断ロジックの変更にあります。
以前の `go test` の実装では、テストパッケージ(内部テストパッケージまたは外部テストパッケージ)をテストバイナリにインポートするかどうかの判断基準として、主にそのパッケージ内にテスト関数(`TestXxx`)やベンチマーク関数(`BenchmarkXxx`)が存在するかどうかを示す `NeedTest` や `NeedXtest` といったブール型フラグが使用されていました。Example関数が存在するだけでは、これらのフラグが `true` にならない場合があり、特に `Output:` コメントを持たない非実行可能なExample関数は、テストバイナリから除外される可能性がありました。
このコミットでは、この問題を解決するために、`testFuncs` 構造体に `ImportTest` と `ImportXtest` という新しいブール型フィールドが導入されました。これらのフィールドは、それぞれ内部テストパッケージと外部テストパッケージがテストバイナリにインポートされるべきかどうかを示す役割を担います。
変更のポイントは以下の通りです。
1. **新しいインポートフラグの導入**: `testFuncs` 構造体に `ImportTest` と `ImportXtest` が追加されました。これらは、テスト関数やベンチマーク関数だけでなく、Example関数が存在する場合にも `true` に設定されるようになります。
2. **`load` 関数のシグネチャ変更**: テストファイルを解析し、テスト関数、ベンチマーク関数、Example関数を検出する `load` 関数のシグネチャが変更されました。これまでの `func (t *testFuncs) load(filename, pkg string, seen *bool) error` から、`func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error` へと変更され、`doImport` という新しいブール型ポインタ引数が追加されました。
3. **Example関数検出時の `doImport` 設定**: `load` 関数内でExample関数が検出された場合、`*doImport = true` が設定されるようになりました。これにより、Example関数が存在するだけで、対応する `ImportTest` または `ImportXtest` フラグが `true` になります。
4. **テストメインのインポート条件の変更**: テストバイナリのメインパッケージを生成する際に使用されるテンプレート(`writeTestmain` 関数内で処理される)の条件式が変更されました。以前は `{{if .NeedTest}}` や `{{if .NeedXtest}}` でインポートを判断していましたが、これが `{{if .ImportTest}}` や `{{if .ImportXtest}}` に変更されました。これにより、Example関数が存在するだけで、そのテストパッケージがテストバイナリにインポートされることが保証されます。
5. **テストケースの追加**: `src/cmd/go/test.bash` に新しいテストケースが追加され、非実行可能なExample関数を含む外部テストパッケージが正しくビルドされることを検証しています。これは、`go test -v ./testdata/norunexample` を実行し、特定の文字列が標準出力に含まれることを確認することで行われます。
これらの変更により、`go test` は、`Output:` コメントを持たないExample関数であっても、それが外部テストパッケージに存在する場合に、そのExample関数を含むファイルをビルドプロセスに含めるようになります。これにより、Example関数内のコードのコンパイル時チェックが保証され、コードの品質と信頼性が向上します。
## コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
* **`src/cmd/go/test.go`**: `go test` コマンドのテスト実行ロジックを定義するGoソースファイル。
* `testFuncs` 構造体に `ImportTest` と `ImportXtest` フィールドが追加されました。
* `load` 関数のシグネチャが変更され、Example関数検出時のインポートフラグ設定ロジックが追加されました。
* `loadTestFuncs` 関数内で `load` 関数を呼び出す際の引数が変更されました。
* `builder` の `test` メソッド内で、テストパッケージをメインパッケージにインポートする条件が `NeedTest`/`NeedXtest` から `ImportTest`/`ImportXtest` に変更されました。
* テストメインのテンプレート(`writeTestmain` 関数内で使用される)のインポート条件が更新されました。
* **`src/cmd/go/test.bash`**: `go` コマンドのテストスイートの一部であるシェルスクリプト。
* 新しいテストケースが追加され、非実行可能なExample関数を含む外部テストパッケージのビルドが検証されます。
* **`src/cmd/go/testdata/norunexample/example_test.go`**: 新規追加されたテストデータファイル。
* `Output:` コメントを持たない非実行可能なExample関数 `Example_test()` が含まれています。
* `init()` 関数で特定の文字列を出力することで、このファイルがビルドされたかどうかを検証できるようにしています。
* **`src/cmd/go/testdata/norunexample/test_test.go`**: 新規追加されたテストデータファイル。
* 通常のテスト関数 `TestBuilt()` が含まれています。
## コアとなるコードの解説
### `src/cmd/go/test.go` の変更点
1. **`testFuncs` 構造体の変更**:
```go
type testFuncs struct {
Tests []testFunc
Benchmarks []testFunc
Examples []testFunc
Package *Package
ImportTest bool // 新規追加: 内部テストパッケージをインポートする必要があるか
NeedTest bool
ImportXtest bool // 新規追加: 外部テストパッケージをインポートする必要があるか
NeedXtest bool
Cover []coverInfo
}
```
`ImportTest` と `ImportXtest` という2つの新しいブール型フィールドが追加されました。これらは、テスト関数やベンチマーク関数が存在するかどうか(`NeedTest`/`NeedXtest`)とは独立して、Example関数が存在する場合にも `true` に設定され、テストパッケージがビルドされるべきであることを示します。
2. **`load` 関数のシグネチャとロジックの変更**:
```go
// 変更前: func (t *testFuncs) load(filename, pkg string, seen *bool) error
// 変更後: func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
// ... (既存のコード) ...
// Test関数やBenchmark関数が見つかった場合
switch {
case isTest(name, "Test"):
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
*doImport, *seen = true, true // ここでdoImportもtrueに設定
case isTest(name, "Benchmark"):
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
*doImport, *seen = true, true // ここでdoImportもtrueに設定
}
// ... (既存のコード) ...
// Example関数が見つかった場合
ex := doc.Examples(f)
sort.Sort(byOrder(ex))
for _, e := range ex {
*doImport = true // Example関数が見つかった場合、doImportをtrueに設定
if e.Output == "" && !e.EmptyOutput {
// OutputコメントがないExampleは実行しない
continue
}
// ... (既存のコード) ...
}
return nil
}
```
`load` 関数は、指定されたテストファイル(`_test.go` または `_xtest.go`)を解析し、その中に含まれるテスト関数、ベンチマーク関数、Example関数を検出します。変更点として、`doImport` という新しい引数が追加され、テスト関数、ベンチマーク関数、またはExample関数が検出された場合に `*doImport = true` が設定されるようになりました。これにより、Example関数が存在するだけでも、そのテストパッケージがインポートされるべきであるという情報が伝達されます。
3. **`loadTestFuncs` 関数内の `load` 呼び出しの変更**:
```go
func loadTestFuncs(ptest *Package) (*testFuncs, error) {
// ... (既存のコード) ...
for _, file := range ptest.TestGoFiles {
// 変更前: if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
return nil, err
}
}
for _, file := range ptest.XTestGoFiles {
// 変更前: if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
return nil, err
}
}
return t, nil
}
```
`loadTestFuncs` 関数は、テスト対象パッケージのテストファイルと外部テストファイルを処理し、`testFuncs` 構造体を構築します。ここで `load` 関数を呼び出す際に、新しく追加された `&t.ImportTest` と `&t.ImportXtest` がそれぞれ `doImport` 引数として渡されるようになりました。これにより、`load` 関数内でExample関数が検出された場合に、これらのフラグが適切に設定されるようになります。
4. **`builder` の `test` メソッド内のインポート条件の変更**:
```go
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
// ... (既存のコード) ...
if t.ImportTest || ptest.coverMode != "" { // 変更前: t.NeedTest || ptest.coverMode != ""
pmain.imports = append(pmain.imports, ptest)
}
if t.ImportXtest { // 変更前: t.NeedXtest
pmain.imports = append(pmain.imports, pxtest)
}
// ... (既存のコード) ...
}
```
`test` メソッドは、テストバイナリのビルドと実行を調整します。ここで、テストメインパッケージ(`pmain`)に内部テストパッケージ(`ptest`)や外部テストパッケージ(`pxtest`)をインポートする条件が変更されました。以前は `NeedTest` や `NeedXtest` に依存していましたが、新しい `ImportTest` や `ImportXtest` フラグを使用するようになりました。これにより、Example関数が存在するだけでも、対応するテストパッケージがテストバイナリにインポートされることが保証されます。
5. **テストメインのテンプレートの変更**:
```go
// 変更前: {{if .NeedTest}}
// 変更後: {{if .ImportTest}}
// 変更前: _test {{.Package.ImportPath | printf "%q"}}
// 変更後: {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
{{end}}
// 変更前: {{if .NeedXtest}}
// 変更後: {{if .ImportXtest}}
// 変更前: _xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
// 変更後: {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{if .ImportXtest}}
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{end}}
```
`writeTestmain` 関数によって生成されるテストバイナリのメインパッケージのGoソースコードテンプレートが変更されました。`import` 文の生成条件が `NeedTest`/`NeedXtest` から `ImportTest`/`ImportXtest` に変更されました。これにより、Example関数が存在するだけで、対応するテストパッケージがテストバイナリに含められるようになります。また、`_test` や `_xtest` のエイリアスを付けるかどうかも `NeedTest`/`NeedXtest` に依存するようになっています。Example関数のみが存在し、テスト関数やベンチマーク関数が存在しない場合は、アンダースコア `_` を使ってパッケージをインポートし、そのパッケージの `init` 関数などが実行されるようにします。
### `src/cmd/go/test.bash` の変更点
```bash
TEST 'go test builds an xtest containing only non-runnable examples'
if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
echo "go test ./testdata/norunexample failed"
ok=false
elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
echo "file with non-runnable example was not built"
ok=false
fi
このシェルスクリプトは、go
コマンドのテストスイートの一部です。新しいテストケースが追加され、go test -v ./testdata/norunexample
を実行し、その出力に File with non-runnable example was built.
という文字列が含まれていることを確認しています。この文字列は、新しく追加された testdata/norunexample/example_test.go
ファイルの init()
関数から出力されるものであり、このテストが成功することで、非実行可能なExample関数を含むファイルが実際にビルドプロセスに含まれたことが検証されます。
src/cmd/go/testdata/norunexample/example_test.go
(新規追加)
package pkg_test
import "os"
func init() {
os.Stdout.Write([]byte("File with non-runnable example was built.\n"))
}
func Example_test() {
// This test will not be run, it has no "Output:" comment.
}
このファイルは、外部テストパッケージ pkg_test
に属し、Output:
コメントを持たない非実行可能なExample関数 Example_test()
を含んでいます。init()
関数で標準出力に特定の文字列を書き出すことで、このファイルが go test
によってビルドされたかどうかを外部から確認できるようにしています。
src/cmd/go/testdata/norunexample/test_test.go
(新規追加)
package pkg
import (
"os"
"testing"
)
func TestBuilt(t *testing.T) {
os.Stdout.Write([]byte("A normal test was executed.\n"))
}
このファイルは、内部テストパッケージ pkg
に属し、通常のテスト関数 TestBuilt()
を含んでいます。これは、go test
がこのディレクトリ内のテストを処理する際に、通常のテストも引き続き正しく機能することを示すためのものです。
これらの変更と新しいテストデータにより、go test
は、Output:
コメントを持たないExample関数であっても、それが外部テストパッケージに存在する場合に、そのExample関数を含むファイルをビルドプロセスに含めるようになり、コードの健全性が向上しました。
関連リンク
- Go Code Review: https://golang.org/cl/108180043
参考にした情報源リンク
- Go Testing: https://go.dev/blog/testing
- Go Example Functions: https://go.dev/blog/examples
- Go
testing
package documentation: https://pkg.go.dev/testing - Stack Overflow discussions on Go
_test
and_xtest
packages. - Stack Overflow discussions on Go example functions.
# [インデックス 19625] ファイルの概要
このコミットは、Go言語の `cmd/go` ツール、特に `go test` コマンドの動作に関するものです。具体的には、外部テストパッケージ(`_xtest`)内に存在する、実行されない(`Output:` コメントを持たない)Example関数を含むファイルが、`go test` 実行時に適切にビルドされるように修正を行っています。これにより、これらのExample関数に含まれるコードがコンパイル時にチェックされ、潜在的なエラーが早期に発見されるようになります。
## コミット
commit ea0fb5d8e2ba795f0fc985da27a9514492abd7bb Author: Andrew Gerrand adg@golang.org Date: Sat Jun 28 07:15:22 2014 +1000
cmd/go: build non-runnable examples in xtests
Include these files in the build,
even though they don't get executed.
LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/108180043
src/cmd/go/test.bash | 8 +++++
src/cmd/go/test.go | 39 +++++++++++++-----------
src/cmd/go/testdata/norunexample/example_test.go | 11 +++++++
src/cmd/go/testdata/norunexample/test_test.go | 10 ++++++
4 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 0060ce2185..c62f629405 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -806,6 +806,14 @@ if ! ./testgo test xtestonly >/dev/null; then fi unset GOPATH
+TEST 'go test builds an xtest containing only non-runnable examples' +if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then +\techo "go test ./testdata/norunexample failed" +\tok=false +elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then +\techo "file with non-runnable example was not built" +\tok=false +fi
clean up
if $started; then stop; fi
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 5935c98db9..a602469e44 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -723,10 +723,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if err != nil {
return nil, nil, nil, err
}\n-\tif t.NeedTest || ptest.coverMode != "" {\n+\tif t.ImportTest || ptest.coverMode != "" {\n \t\tpmain.imports = append(pmain.imports, ptest)\n \t}\n-\tif t.NeedTest || ptest.coverMode != "" {\n+\tif t.ImportTest || ptest.coverMode != "" {\n \t\tpmain.imports = append(pmain.imports, ptest)\n \t}\n-\tif t.NeedXtest {\n+\tif t.ImportXtest {\n \t\tpmain.imports = append(pmain.imports, pxtest)\n \t}\n \n@@ -1082,12 +1082,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {\n \tPackage: ptest,\n \t}\n for _, file := range ptest.TestGoFiles {\n-\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {\n+\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {\n \t\t\treturn nil, err\n \t\t}\n \t}\n \tfor _, file := range ptest.XTestGoFiles {\n-\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {\n+\t\tif err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {\n \t\t\treturn nil, err\n \t\t}\n \t}\n@@ -1110,13 +1110,15 @@ func writeTestmain(out string, t *testFuncs) error {\n }\n \n type testFuncs struct {\n-\tTests []testFunc\n-\tBenchmarks []testFunc\n-\tExamples []testFunc\n-\tPackage *Package\n-\tNeedTest bool\n-\tNeedXtest bool\n-\tCover []coverInfo\n+\tTests []testFunc\n+\tBenchmarks []testFunc\n+\tExamples []testFunc\n+\tPackage *Package\n+\tImportTest bool\n+\tNeedTest bool\n+\tImportXtest bool\n+\tNeedXtest bool\n+\tCover []coverInfo\n }\n \n func (t *testFuncs) CoverMode() string {\n@@ -1151,7 +1153,7 @@ type testFunc struct {\n \n var testFileSet = token.NewFileSet()\n \n-func (t *testFuncs) load(filename, pkg string, seen *bool) error {\n+func (t *testFuncs) load(filename, pkg string, doImport, seen bool) error {\n \tf, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)\n \tif err != nil {\n \t\treturn expandScanner(err)\n@@ -1168,15 +1170,16 @@ func (t testFuncs) load(filename, pkg string, seen bool) error {\n \t\tswitch {\n \t\tcase isTest(name, "Test"):\n \t\t\tt.Tests = append(t.Tests, testFunc{pkg, name, ""})\n-\t\t\tseen = true\n+\t\t\tdoImport, seen = true, true\n \t\tcase isTest(name, "Benchmark"):\n \t\t\tt.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})\n-\t\t\tseen = true\n+\t\t\tdoImport, seen = true, true\n \t\t}\n \t}\n \tex := doc.Examples(f)\n \tsort.Sort(byOrder(ex))\n \tfor _, e := range ex {\n+\t\tdoImport = true // import test file whether executed or not\n \t\tif e.Output == "" && !e.EmptyOutput {\n \t\t\t// Don't run examples with no output.\n \t\t\tcontinue\n@@ -1200,11 +1203,11 @@ import (\n \t"regexp"\n \t"testing"\n \n-{{if .NeedTest}}\n-\t_test {{.Package.ImportPath | printf "%q"}}\n+{{if .ImportTest}}\n+\t{{if .NeedTest}}test{{else}}{{end}} {{.Package.ImportPath | printf "%q"}}\n {{end}}\n-{{if .NeedXtest}}\n-\t_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}\n+{{if .ImportXtest}}\n+\t{{if .NeedXtest}}xtest{{else}}{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}\n {{end}}\n {{range $i, $p := .Cover}}\n \t_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}\ndiff --git a/src/cmd/go/testdata/norunexample/example_test.go b/src/cmd/go/testdata/norunexample/example_test.go
new file mode 100644
index 0000000000..e158305a6c
--- /dev/null
+++ b/src/cmd/go/testdata/norunexample/example_test.go
@@ -0,0 +1,11 @@
+package pkg_test
+
+import "os"
+
+func init() {
+\tos.Stdout.Write([]byte("File with non-runnable example was built.\n"))
+}\n+\n+func Example_test() {
+\t// This test will not be run, it has no "Output:" comment.
+}\ndiff --git a/src/cmd/go/testdata/norunexample/test_test.go b/src/cmd/go/testdata/norunexample/test_test.go
new file mode 100644
index 0000000000..d2e919838f
--- /dev/null
+++ b/src/cmd/go/testdata/norunexample/test_test.go
@@ -0,0 +1,10 @@
+package pkg
+
+import (
+\t"os"
+\t"testing"
+)\n+\n+func TestBuilt(t *testing.T) {
+\tos.Stdout.Write([]byte("A normal test was executed.\n"))
+}\n```
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ea0fb5d8e2ba795f0fc985da27a9514492abd7bb
元コミット内容
cmd/go
: 外部テストパッケージ(xtests
)内の非実行可能なExample関数をビルドする。
これらのファイルは実行されないにもかかわらず、ビルドに含める。
変更の背景
Goの go test
コマンドは、テスト関数(TestXxx
)、ベンチマーク関数(BenchmarkXxx
)、およびExample関数(ExampleXxx
)を検出して実行します。Example関数は、コードの利用例を示すために使用され、// Output:
コメントを持つ場合はその出力が検証されます。しかし、// Output:
コメントを持たないExample関数(非実行可能なExample)は、通常は実行されません。
このコミット以前は、go test
が外部テストパッケージ(_xtest
)内の非実行可能なExample関数を含むファイルを適切にビルドしないという問題がありました。これは、これらのExample関数に含まれるコードがコンパイル時にチェックされず、構文エラーや型エラーなどの問題が見過ごされる可能性を意味していました。開発者がExample関数を記述する目的の一つは、そのコードが常に有効であることを保証することでもあるため、ビルドプロセスから除外されることは望ましくありませんでした。
この変更は、非実行可能なExample関数であっても、それが外部テストパッケージに存在する場合に、go test
がそのファイルをビルドプロセスに含めるようにすることで、この問題を解決することを目的としています。これにより、Example関数が単なるドキュメントとしてだけでなく、コードの健全性を保証する役割も果たすようになります。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語のテストに関する概念と go test
コマンドの内部動作に関する知識が必要です。
go test
コマンド
go test
はGo言語の標準的なテスト実行ツールです。指定されたパッケージ内のテストファイル(_test.go
で終わるファイル)をコンパイルし、テスト関数、ベンチマーク関数、Example関数を実行します。
_test.go
ファイル
Goのテストコードは、テスト対象のGoファイルと同じディレクトリに配置され、ファイル名が _test.go
で終わる必要があります(例: my_package_test.go
)。これらのファイルは通常のビルドプロセスからは除外されますが、go test
コマンドが実行される際にコンパイルされ、テストバイナリに含められます。
内部テストパッケージ (Internal Test Package)
テストファイルが、テスト対象のパッケージと同じパッケージ名(例: package mypackage
)を宣言している場合、それは「内部テストパッケージ」と呼ばれます。この場合、テストコードはテスト対象パッケージの非公開(unexported)な識別子(関数、変数、構造体フィールドなど)にも直接アクセスできます。これは、パッケージの内部実装の詳細をテストするユニットテストに適しています。
外部テストパッケージ (External Test Package)
テストファイルが、テスト対象のパッケージ名に _test
サフィックスを付けたパッケージ名(例: package mypackage_test
)を宣言している場合、それは「外部テストパッケージ」と呼ばれます。この場合、テストコードはテスト対象パッケージを明示的にインポートする必要があります(例: import "your_module/mypackage"
)。外部テストパッケージは、テスト対象パッケージの公開(exported)な識別子にのみアクセスできます。これは、パッケージを外部の利用者の視点からテストする「ブラックボックステスト」に適しており、パッケージの公開APIと振る舞いに焦点を当てたテストを書く際に推奨されます。このコミットで言及されている xtests
は、この外部テストパッケージを指します。
GoのExample関数
Example関数は、Example
プレフィックスを持つ関数で、_test.go
ファイル内に記述されます。これらは、パッケージ、関数、型、またはメソッドの利用例を示すために使用されます。
- 実行可能なExample: Example関数の最後に
// Output: expected output
の形式でコメントが記述されている場合、go test
はそのExample関数を実行し、標準出力に書き込まれた内容がexpected output
と一致するかどうかを検証します。これにより、ドキュメントとしてのExampleが常に正しく動作することを保証できます。 - 非実行可能なExample: Example関数に
// Output:
コメントがない場合、go test
はそのExample関数をコンパイルしますが、実行はしません。これらのExampleは、主にドキュメント目的で使用され、コードの利用方法を示すためのものです。このコミットの焦点は、まさにこの「非実行可能なExample」が_xtest
に存在する場合のビルド動作にあります。
技術的詳細
このコミットの技術的な核心は、go test
コマンドがテストバイナリを生成する際の、テストパッケージのインポート判断ロジックの変更にあります。
以前の go test
の実装では、テストパッケージ(内部テストパッケージまたは外部テストパッケージ)をテストバイナリにインポートするかどうかの判断基準として、主にそのパッケージ内にテスト関数(TestXxx
)やベンチマーク関数(BenchmarkXxx
)が存在するかどうかを示す NeedTest
や NeedXtest
といったブール型フラグが使用されていました。Example関数が存在するだけでは、これらのフラグが true
にならない場合があり、特に Output:
コメントを持たない非実行可能なExample関数は、テストバイナリから除外される可能性がありました。
このコミットでは、この問題を解決するために、testFuncs
構造体に ImportTest
と ImportXtest
という新しいブール型フィールドが導入されました。これらのフィールドは、それぞれ内部テストパッケージと外部テストパッケージがテストバイナリにインポートされるべきかどうかを示す役割を担います。
変更のポイントは以下の通りです。
- 新しいインポートフラグの導入:
testFuncs
構造体にImportTest
とImportXtest
が追加されました。これらは、テスト関数やベンチマーク関数だけでなく、Example関数が存在する場合にもtrue
に設定されるようになります。 load
関数のシグネチャ変更: テストファイルを解析し、テスト関数、ベンチマーク関数、Example関数を検出するload
関数のシグネチャが変更されました。これまでのfunc (t *testFuncs) load(filename, pkg string, seen *bool) error
から、func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error
へと変更され、doImport
という新しいブール型ポインタ引数が追加されました。- Example関数検出時の
doImport
設定:load
関数内でExample関数が検出された場合、*doImport = true
が設定されるようになりました。これにより、Example関数が存在するだけでも、対応するImportTest
またはImportXtest
フラグがtrue
になります。 - テストメインのインポート条件の変更: テストバイナリのメインパッケージを生成する際に使用されるテンプレート(
writeTestmain
関数内で処理される)の条件式が変更されました。以前は{{if .NeedTest}}
や{{if .NeedXtest}}
でインポートを判断していましたが、これが{{if .ImportTest}}
や{{if .ImportXtest}}
に変更されました。これにより、Example関数が存在するだけで、そのテストパッケージがテストバイナリにインポートされることが保証されます。 - テストケースの追加:
src/cmd/go/test.bash
に新しいテストケースが追加され、非実行可能なExample関数を含む外部テストパッケージが正しくビルドされることを検証しています。これは、go test -v ./testdata/norunexample
を実行し、特定の文字列が標準出力に含まれることを確認することで行われます。
これらの変更により、go test
は、Output:
コメントを持たないExample関数であっても、それが外部テストパッケージに存在する場合に、そのExample関数を含むファイルをビルドプロセスに含めるようになります。これにより、Example関数内のコードのコンパイル時チェックが保証され、コードの品質と信頼性が向上します。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
src/cmd/go/test.go
:go test
コマンドのテスト実行ロジックを定義するGoソースファイル。testFuncs
構造体にImportTest
とImportXtest
フィールドが追加されました。load
関数のシグネチャが変更され、Example関数検出時のインポートフラグ設定ロジックが追加されました。loadTestFuncs
関数内でload
関数を呼び出す際の引数が変更されました。builder
のtest
メソッド内で、テストパッケージをメインパッケージにインポートする条件がNeedTest
/NeedXtest
からImportTest
/ImportXtest
に変更されました。- テストメインのテンプレート(
writeTestmain
関数内で使用される)のインポート条件が更新されました。
src/cmd/go/test.bash
:go
コマンドのテストスイートの一部であるシェルスクリプト。- 新しいテストケースが追加され、非実行可能なExample関数を含む外部テストパッケージのビルドが検証されます。
src/cmd/go/testdata/norunexample/example_test.go
: 新規追加されたテストデータファイル。Output:
コメントを持たない非実行可能なExample関数Example_test()
が含まれています。init()
関数で特定の文字列を出力することで、このファイルがビルドされたかどうかを検証できるようにしています。
src/cmd/go/testdata/norunexample/test_test.go
: 新規追加されたテストデータファイル。- 通常のテスト関数
TestBuilt()
が含まれています。
- 通常のテスト関数
コアとなるコードの解説
src/cmd/go/test.go
の変更点
-
testFuncs
構造体の変更:type testFuncs struct { Tests []testFunc Benchmarks []testFunc Examples []testFunc Package *Package ImportTest bool // 新規追加: 内部テストパッケージをインポートする必要があるか NeedTest bool ImportXtest bool // 新規追加: 外部テストパッケージをインポートする必要があるか NeedXtest bool Cover []coverInfo }
ImportTest
とImportXtest
という2つの新しいブール型フィールドが追加されました。これらは、テスト関数やベンチマーク関数が存在するかどうか(NeedTest
/NeedXtest
)とは独立して、Example関数が存在する場合にもtrue
に設定され、テストパッケージがビルドされるべきであることを示します。 -
load
関数のシグネチャとロジックの変更:// 変更前: func (t *testFuncs) load(filename, pkg string, seen *bool) error // 変更後: func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { // ... (既存のコード) ... // Test関数やBenchmark関数が見つかった場合 switch { case isTest(name, "Test"): t.Tests = append(t.Tests, testFunc{pkg, name, ""}) *doImport, *seen = true, true // ここでdoImportもtrueに設定 case isTest(name, "Benchmark"): t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""}) *doImport, *seen = true, true // ここでdoImportもtrueに設定 } // ... (既存のコード) ... // Example関数が見つかった場合 ex := doc.Examples(f) sort.Sort(byOrder(ex)) for _, e := range ex { *doImport = true // Example関数が見つかった場合、doImportをtrueに設定 if e.Output == "" && !e.EmptyOutput { // OutputコメントがないExampleは実行しない continue } // ... (既存のコード) ... } return nil }
load
関数は、指定されたテストファイル(_test.go
または_xtest.go
)を解析し、その中に含まれるテスト関数、ベンチマーク関数、Example関数を検出します。変更点として、doImport
という新しい引数が追加され、テスト関数、ベンチマーク関数、またはExample関数が検出された場合に*doImport = true
が設定されるようになりました。これにより、Example関数が存在するだけでも、そのテストパッケージがインポートされるべきであるという情報が伝達されます。 -
loadTestFuncs
関数内のload
呼び出しの変更:func loadTestFuncs(ptest *Package) (*testFuncs, error) { // ... (既存のコード) ... for _, file := range ptest.TestGoFiles { // 変更前: if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil { if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil { return nil, err } } for _, file := range ptest.XTestGoFiles { // 変更前: if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil { if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil { return nil, err } } return t, nil }
loadTestFuncs
関数は、テスト対象パッケージのテストファイルと外部テストファイルを処理し、testFuncs
構造体を構築します。ここでload
関数を呼び出す際に、新しく追加された&t.ImportTest
と&t.ImportXtest
がそれぞれdoImport
引数として渡されるようになりました。これにより、load
関数内でExample関数が検出された場合に、これらのフラグが適切に設定されるようになります。 -
builder
のtest
メソッド内のインポート条件の変更:func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { // ... (既存のコード) ... if t.ImportTest || ptest.coverMode != "" { // 変更前: t.NeedTest || ptest.coverMode != "" pmain.imports = append(pmain.imports, ptest) } if t.ImportXtest { // 変更前: t.NeedXtest pmain.imports = append(pmain.imports, pxtest) } // ... (既存のコード) ... }
test
メソッドは、テストバイナリのビルドと実行を調整します。ここで、テストメインパッケージ(pmain
)に内部テストパッケージ(ptest
)や外部テストパッケージ(pxtest
)をインポートする条件が変更されました。以前はNeedTest
やNeedXtest
に依存していましたが、新しいImportTest
やImportXtest
フラグを使用するようになりました。これにより、Example関数が存在するだけでも、対応するテストパッケージがテストバイナリにインポートされることが保証されます。 -
テストメインのテンプレートの変更:
// 変更前: {{if .NeedTest}} // 変更後: {{if .ImportTest}} // 変更前: _test {{.Package.ImportPath | printf "%q"}} // 変更後: {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} {{if .ImportTest}} {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} {{end}} // 変更前: {{if .NeedXtest}} // 変更後: {{if .ImportXtest}} // 変更前: _xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}} // 変更後: {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} {{if .ImportXtest}} {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} {{end}}
writeTestmain
関数によって生成されるテストバイナリのメインパッケージのGoソースコードテンプレートが変更されました。import
文の生成条件がNeedTest
/NeedXtest
からImportTest
/ImportXtest
に変更されました。これにより、Example関数が存在するだけで、対応するテストパッケージがテストバイナリに含められるようになります。また、_test
や_xtest
のエイリアスを付けるかどうかもNeedTest
/NeedXtest
に依存するようになっています。Example関数のみが存在し、テスト関数やベンチマーク関数が存在しない場合は、アンダースコア_
を使ってパッケージをインポートし、そのパッケージのinit
関数などが実行されるようにします。
src/cmd/go/test.bash
の変更点
TEST 'go test builds an xtest containing only non-runnable examples'
if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
echo "go test ./testdata/norunexample failed"
ok=false
elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
echo "file with non-runnable example was not built"
ok=false
fi
このシェルスクリプトは、go
コマンドのテストスイートの一部です。新しいテストケースが追加され、go test -v ./testdata/norunexample
を実行し、その出力に File with non-runnable example was built.
という文字列が含まれていることを確認しています。この文字列は、新しく追加された testdata/norunexample/example_test.go
ファイルの init()
関数から出力されるものであり、このテストが成功することで、非実行可能なExample関数を含むファイルが実際にビルドプロセスに含まれたことが検証されます。
src/cmd/go/testdata/norunexample/example_test.go
(新規追加)
package pkg_test
import "os"
func init() {
os.Stdout.Write([]byte("File with non-runnable example was built.\n"))
}
func Example_test() {
// This test will not be run, it has no "Output:" comment.
}
このファイルは、外部テストパッケージ pkg_test
に属し、Output:
コメントを持たない非実行可能なExample関数 Example_test()
を含んでいます。init()
関数で標準出力に特定の文字列を書き出すことで、このファイルが go test
によってビルドされたかどうかを外部から確認できるようにしています。
src/cmd/go/testdata/norunexample/test_test.go
(新規追加)
package pkg
import (
"os"
"testing"
)
func TestBuilt(t *testing.T) {
os.Stdout.Write([]byte("A normal test was executed.\n"))
}
このファイルは、内部テストパッケージ pkg
に属し、通常のテスト関数 TestBuilt()
を含んでいます。これは、go test
がこのディレクトリ内のテストを処理する際に、通常のテストも引き続き正しく機能することを示すためのものです。
これらの変更と新しいテストデータにより、go test
は、Output:
コメントを持たないExample関数であっても、それが外部テストパッケージに存在する場合に、そのExample関数を含むファイルをビルドプロセスに含めるようになり、コードの健全性が向上しました。
関連リンク
- Go Code Review: https://golang.org/cl/108180043
参考にした情報源リンク
- Go Testing: https://go.dev/blog/testing
- Go Example Functions: https://go.dev/blog/examples
- Go
testing
package documentation: https://pkg.go.dev/testing - Stack Overflow discussions on Go
_test
and_xtest
packages. - Stack Overflow discussions on Go example functions.