Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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関数を含むファイルをビルドプロセスに含めるようになり、コードの健全性が向上しました。

関連リンク

参考にした情報源リンク

# [インデックス 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)が存在するかどうかを示す NeedTestNeedXtest といったブール型フラグが使用されていました。Example関数が存在するだけでは、これらのフラグが true にならない場合があり、特に Output: コメントを持たない非実行可能なExample関数は、テストバイナリから除外される可能性がありました。

このコミットでは、この問題を解決するために、testFuncs 構造体に ImportTestImportXtest という新しいブール型フィールドが導入されました。これらのフィールドは、それぞれ内部テストパッケージと外部テストパッケージがテストバイナリにインポートされるべきかどうかを示す役割を担います。

変更のポイントは以下の通りです。

  1. 新しいインポートフラグの導入: testFuncs 構造体に ImportTestImportXtest が追加されました。これらは、テスト関数やベンチマーク関数だけでなく、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 構造体に ImportTestImportXtest フィールドが追加されました。
    • load 関数のシグネチャが変更され、Example関数検出時のインポートフラグ設定ロジックが追加されました。
    • loadTestFuncs 関数内で load 関数を呼び出す際の引数が変更されました。
    • buildertest メソッド内で、テストパッケージをメインパッケージにインポートする条件が 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 構造体の変更:

    type testFuncs struct {
    	Tests       []testFunc
    	Benchmarks  []testFunc
    	Examples    []testFunc
    	Package     *Package
    	ImportTest  bool // 新規追加: 内部テストパッケージをインポートする必要があるか
    	NeedTest    bool
    	ImportXtest bool // 新規追加: 外部テストパッケージをインポートする必要があるか
    	NeedXtest   bool
    	Cover       []coverInfo
    }
    

    ImportTestImportXtest という2つの新しいブール型フィールドが追加されました。これらは、テスト関数やベンチマーク関数が存在するかどうか(NeedTest/NeedXtest)とは独立して、Example関数が存在する場合にも true に設定され、テストパッケージがビルドされるべきであることを示します。

  2. 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関数が存在するだけでも、そのテストパッケージがインポートされるべきであるという情報が伝達されます。

  3. 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関数が検出された場合に、これらのフラグが適切に設定されるようになります。

  4. buildertest メソッド内のインポート条件の変更:

    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)をインポートする条件が変更されました。以前は NeedTestNeedXtest に依存していましたが、新しい ImportTestImportXtest フラグを使用するようになりました。これにより、Example関数が存在するだけでも、対応するテストパッケージがテストバイナリにインポートされることが保証されます。

  5. テストメインのテンプレートの変更:

    // 変更前: {{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関数を含むファイルをビルドプロセスに含めるようになり、コードの健全性が向上しました。

関連リンク

参考にした情報源リンク