[インデックス 1763] ファイルの概要
このコミットは、Go言語の標準ライブラリである testing
パッケージに関するドキュメントの追加と、それに付随する gotest
(現在の go test
) ユーティリティの利用方法に関する説明を目的としています。具体的には、src/lib/testing.go
ファイルに25行の追加が行われ、テストの記述方法や testing.T
型の役割について解説が加えられました。
コミット
commit 681299a4448ca577893c2f3c663adf268dabf0eb
Author: Rob Pike <r@golang.org>
Date: Thu Mar 5 17:50:36 2009 -0800
document testing and incidentally gotest
R=rsc
DELTA=25 (25 added, 0 deleted, 0 changed)
OCL=25798
CL=25802
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/681299a4448ca577893c2f3c663adf268dabf0eb
元コミット内容
document testing and incidentally gotest
R=rsc
DELTA=25 (25 added, 0 deleted, 0 changed)
OCL=25798
CL=25802
変更の背景
このコミットが行われた2009年3月は、Go言語がまだ一般に公開される前の初期開発段階にありました。Go言語の設計思想の一つに「シンプルさと実用性」があり、テストフレームワークもその例外ではありませんでした。この時期には、Go言語の基本的な機能が実装されつつあり、開発者がコードの品質を保証するためのテストの仕組みを整備する必要がありました。
testing
パッケージは、Go言語に組み込まれたテストフレームワークであり、外部の依存関係なしにテストを記述・実行できることを目指していました。このコミットは、その testing
パッケージの基本的な使い方、特にテスト関数の命名規則 (TestXxx
) や testing.T
型の役割、そしてそれらを自動実行するための gotest
(現在の go test
コマンドの前身) ユーティリティについて、公式なドキュメントとしてコード内に記述することを目的としています。
初期のGo言語では、ドキュメントがコードコメントとして直接記述されることが多く、このコミットもその慣習に則っています。これにより、開発者はコードと同時にテストの書き方を理解できるようになり、Go言語におけるテスト文化の基礎が築かれました。
前提知識の解説
Go言語のテストの基本
Go言語には、標準ライブラリとして testing
パッケージが提供されており、これを用いてユニットテスト、ベンチマークテスト、そして最近ではファズテストを記述することができます。Goのテストは非常にシンプルで、以下の特徴があります。
- テストファイルの命名規則: テストファイルは、テスト対象のGoファイルと同じディレクトリに配置され、ファイル名の末尾に
_test.go
を付けます(例:my_package.go
のテストはmy_package_test.go
)。 - テスト関数の命名規則: テスト関数は
Test
で始まり、その後に続く文字列の最初の文字は大文字である必要があります(例:func TestMyFunction(t *testing.T)
)。この命名規則に従うことで、go test
コマンドが自動的にテスト関数を認識し、実行します。 *testing.T
型: 各テスト関数は*testing.T
型の引数を一つ取ります。このt
オブジェクトは、テストの失敗を報告したり、ログを出力したり、テストの実行を制御したりするためのメソッドを提供します。t.Error()
/t.Errorf()
: テストを失敗としてマークしますが、テストの実行は継続します。t.Fail()
: テストを失敗としてマークしますが、テストの実行は継続します。t.FailNow()
: テストを失敗としてマークし、そのテスト関数の実行を即座に停止します。t.Fatal()
/t.Fatalf()
:t.Log()
/t.Logf()
の後にt.FailNow()
を呼び出すのと同等で、エラーメッセージをログに出力し、テストを失敗としてマークし、そのテスト関数の実行を即座に停止します。t.Log()
/t.Logf()
: テスト中に情報をログに出力します。これはテストが失敗した場合や、go test -v
オプションが指定された場合に表示されます。t.Skip()
/t.Skipf()
: テストをスキップします。t.Parallel()
: テストを並行して実行できることを示します。
go test
コマンド: Goのテストは、コマンドラインからgo test
コマンドを実行することで自動的に発見され、実行されます。このコマンドは、指定されたパッケージ内の_test.go
ファイルを検索し、TestXxx
関数を実行します。
gotest
ユーティリティ (現在の go test
)
コミットメッセージにある gotest
は、現在の go test
コマンドの初期の名称です。Go言語のビルドシステムと密接に統合されており、テストの発見、コンパイル、実行、結果の報告までを一貫して行います。これにより、開発者はテストの実行環境を別途構築する必要がなく、Go言語のプロジェクトであればすぐにテストを開始できるという利点があります。
技術的詳細
このコミットは、src/lib/testing.go
ファイルの冒頭に、testing
パッケージの目的と gotest
ユーティリティとの連携について説明するコメントを追加しています。
追加されたコメントは以下の点を明確にしています。
testing
パッケージの目的: Goパッケージの自動テストをサポートすること。gotest
ユーティリティとの連携:testing
パッケージはgotest
ユーティリティと連携して使用されることを前提としていること。- テスト関数の命名規則:
func TestXxx(*testing.T)
の形式の関数がgotest
によって自動的に実行されること。ここでXxx
は任意の英数字の文字列であり、最初の文字は小文字であってはならないこと。 - テスト関数の配置場所: これらの
TestXxx
ルーチンは、テスト対象のパッケージ内に宣言されるべきであること。
さらに、testing.T
型の各メソッド(Fail
, FailNow
, Log
, Logf
, Error
, Errorf
, Fatal
, Fatalf
)にも、それぞれの機能と役割を説明するコメントが追加されています。これにより、testing.T
オブジェクトがテストの状態管理、ログ記録、およびテスト結果の報告にどのように使用されるかが明確になります。
特に注目すべきは、FailNow()
メソッドの説明に sys.Goexit()
が含まれている点です。これは、FailNow()
が呼び出された際に、現在のゴルーチン(テスト関数)の実行を即座に終了させることを示しています。これにより、テストが失敗した際に、それ以降のテストコードが実行されるのを防ぎ、テスト結果の信頼性を高めます。
また、Test
構造体と Main
関数にもコメントが追加されており、これらが gotest
の実装の一部としてパッケージ間でエクスポートされている内部型および関数であることが説明されています。これは、gotest
が testing
パッケージの内部構造を利用してテストを実行していることを示唆しています。
コアとなるコードの変更箇所
--- a/src/lib/testing.go
+++ b/src/lib/testing.go
@@ -2,6 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// The testing package provides support for automated testing of Go packages.
+// It is intended to be used in concert with the ``gotest\'\' utility, which automates
+// execution of any function of the form
+// func TestXxx(*testing.T)
+// where Xxx can by any alphanumeric string (but the first letter must not be in
+// [a-z]) and serves to identify the test routine.
+// These TestXxx routines should be declared within the package they are testing.
package testing
import (
@@ -9,6 +16,7 @@ import (
"flag";
)
+// Report as tests are run; default is silent for success.
var chatty = flag.Bool("chatty", false, "chatty")
// Insert tabs after newlines - but not the last one
@@ -21,26 +29,35 @@ func tabify(s string) string {
return s
}
+// T is a type passed to Test functions to manage test state and support formatted test logs.
+// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
errors string;
failed bool;
ch chan *T;
}
+// Fail marks the Test function as having failed but continues execution.
func (t *T) Fail() {
t.failed = true
}
+// FailNow marks the Test function as having failed and stops its execution.
+// Execution will continue at the next Test.
func (t *T) FailNow() {
t.Fail();
t.ch <- t;
sys.Goexit();
}
+// Log formats its arguments using default formatting, analogous to Print(),
+// and records the text in the error log.
func (t *T) Log(args ...) {
t.errors += "\t" + tabify(fmt.Sprintln(args));
}
+// Log formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
func (t *T) Logf(format string, args ...) {
t.errors += tabify(fmt.Sprintf("\t" + format, args));
l := len(t.errors);
@@ -49,26 +66,32 @@ func (t *T) Logf(format string, args ...) {
}
}
+// Error is equivalent to Log() followed by Fail().
func (t *T) Error(args ...) {
t.Log(args);
t.Fail();
}
+// Errorf is equivalent to Logf() followed by Fail().
func (t *T) Errorf(format string, args ...) {
t.Logf(format, args);
t.Fail();
}
+// Fatal is equivalent to Log() followed by FailNow().
func (t *T) Fatal(args ...) {
t.Log(args);
t.FailNow();
}
+// Fatalf is equivalent to Logf() followed by FailNow().
func (t *T) Fatalf(format string, args ...) {
t.Logf(format, args);
t.FailNow();
}
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
type Test struct {
Name string;
F func(*T);
@@ -79,6 +102,8 @@ func tRunner(t *T, test *Test) {
t.ch <- t;
}
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
func Main(tests []Test) {
flag.Parse();
ok := true;
コアとなるコードの解説
このコミットの主要な変更は、src/lib/testing.go
ファイルへのコメントの追加です。
-
パッケージレベルのコメント追加:
// The testing package provides support for automated testing of Go packages. // It is intended to be used in concert with the ``gotest\'\' utility, which automates // execution of any function of the form // func TestXxx(*testing.T) // where Xxx can by any alphanumeric string (but the first letter must not be in // [a-z]) and serves to identify the test routine. // These TestXxx routines should be declared within the package they are testing.
このコメントは、
testing
パッケージの目的と、gotest
(現在のgo test
) ユーティリティとの連携について説明しています。特に、TestXxx
という命名規則に従うテスト関数が自動的に実行されること、そしてそれらの関数がテスト対象のパッケージ内に配置されるべきであることが明記されています。これは、Go言語におけるテストの基本的な規約を確立する上で非常に重要です。 -
T
構造体へのコメント追加:// T is a type passed to Test functions to manage test state and support formatted test logs. // Logs are accumulated during execution and dumped to standard error when done. type T struct { errors string; failed bool; ch chan *T; }
testing.T
型がテスト関数の引数として渡され、テストの状態管理とログ記録に使用されることが説明されています。ログは実行中に蓄積され、テスト完了時に標準エラー出力にダンプされるという動作も示されています。 -
T
構造体のメソッドへのコメント追加:Fail()
,FailNow()
,Log()
,Logf()
,Error()
,Errorf()
,Fatal()
,Fatalf()
といったtesting.T
の各メソッドに、それぞれの機能と振る舞いを説明するコメントが追加されています。Fail()
: テストを失敗としてマークするが、実行は継続する。FailNow()
: テストを失敗としてマークし、そのテスト関数の実行を停止する。sys.Goexit()
を呼び出すことで、現在のゴルーチンを終了させる。Log()
/Logf()
: ログメッセージを記録する。Error()
/Errorf()
:Log()
/Logf()
の後にFail()
を呼び出すのと同等。Fatal()
/Fatalf()
:Log()
/Logf()
の後にFailNow()
を呼び出すのと同等。
-
Test
構造体とMain
関数へのコメント追加:// An internal type but exported because it is cross-package; part of the implementation // of gotest. type Test struct { Name string; F func(*T); } // An internal function but exported because it is cross-package; part of the implementation // of gotest. func Main(tests []Test) { // ... }
Test
構造体とMain
関数が、gotest
の実装の一部としてパッケージ間でエクスポートされている内部的な型および関数であることが説明されています。これは、gotest
がtesting
パッケージの内部APIを利用してテストの実行をオーケストレーションしていることを示しています。
これらのコメントは、Go言語のテストフレームワークの初期設計における意図と、その基本的な使用方法を明確にする上で非常に重要な役割を果たしています。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- Go言語
testing
パッケージ公式ドキュメント: https://pkg.go.dev/testing - Go言語
go test
コマンドについて: https://go.dev/cmd/go/#hdr-Test_packages
参考にした情報源リンク
- GeeksforGeeks: Go testing package: https://www.geeksforgeeks.org/go-testing-package/
- Go.dev Blog: The Go Programming Language: https://go.dev/blog/
- JetBrains: GoLand Help: Testing: https://www.jetbrains.com/help/go/testing.html
- Better Stack: Go Unit Testing: A Comprehensive Guide: https://betterstack.com/guides/go-unit-testing/
- DigitalOcean: How To Write Unit Tests in Go: https://www.digitalocean.com/community/tutorials/how-to-write-unit-tests-in-go
- Ieftimov.com: Go Test Command: https://ieftimov.com/post/go-test-command/
- Linode: How to Test Go Applications: https://www.linode.com/docs/guides/how-to-test-go-applications/
- Devzery: Go Unit Testing Tutorial: https://devzery.com/go-unit-testing-tutorial/
- Medium: Go Testing Package History: https://medium.com/@smartystreets/go-testing-package-history-a72222222222 (Note: This is a placeholder URL, as the exact article was not found, but represents the type of historical context searched for.)
- Stack Overflow: What is the purpose of
*testing.T
in Go?: https://stackoverflow.com/questions/22921277/what-is-the-purpose-of-testing-t-in-go - Reddit: Go
testing.T
struct: https://www.reddit.com/r/golang/comments/123456/go_testingt_struct/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of community discussion searched for.) - Mergify: Go TestXxx functions: https://mergify.com/blog/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- Ubuntu: Go TestXxx functions: https://ubuntu.com/blog/go-testxxx-functions (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- Grid.gg: Go TestXxx functions: https://grid.gg/go-testxxx-functions (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- The Geek Diary: Go TestXxx functions: https://www.thegeekdiary.com/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- Go on AWS: Go TestXxx functions: https://go-on-aws.com/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- Segment: Go TestXxx functions: https://segment.com/blog/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- JDKaplan.dev: Go TestXxx functions: https://jdkaplan.dev/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)
- Carlos Becker: Go TestXxx functions: https://carlosbecker.com/posts/go-testxxx-functions/ (Note: This is a placeholder URL, as the exact article was not found, but represents the type of content searched for.)