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

[インデックス 1195] ファイルの概要

このコミットは、Go言語の標準ライブラリの一部であるcontainer/arrayパッケージのテストファイルsrc/lib/container/array/testarray.goに対する変更です。具体的には、Go言語に導入された新しいテストフレームワーク(testingパッケージ)を使用するように、既存のテストコードを更新しています。これにより、テストの失敗をより適切に報告し、Goの標準的なテスト実行ツール(go testコマンド)との互換性を確保しています。

コミット

commit 9195c22e7c9f2d1ad63194644de3493f2b7ec028
Author: Robert Griesemer <gri@golang.org>
Date:   Wed Nov 19 15:17:58 2008 -0800

    use new test framework in array test
    
    R=r
    DELTA=30  (2 added, 5 deleted, 23 changed)
    OCL=19627
    CL=19632

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/9195c22e7c9f2d1ad63194644de3493f2b7ec028

元コミット内容

このコミットの目的は、arrayパッケージのテストコードを、Go言語の新しいテストフレームワークに移行することです。以前のテストは、ブール値を返す関数として実装されており、テストの成功/失敗をtrue/falseで示していました。この変更により、testingパッケージが提供する*testing.T型を引数として受け取り、テストの失敗をt.FailNow()メソッドで報告する形式に更新されています。

変更の背景

Go言語は、その初期段階において、言語仕様や標準ライブラリが活発に開発されていました。このコミットが行われた2008年11月は、Go言語が一般に公開される前の時期であり、言語のコア機能や開発ツールがまだ固まっていない段階でした。

この時期に、Go言語のテストの仕組みが進化し、より堅牢で標準化されたtestingパッケージが導入されました。それ以前のテストは、単純なブール値を返す関数として記述されることが多く、テストの失敗時に詳細な情報を提供したり、テストの実行を制御したりする機能が限られていました。

新しいtestingパッケージは、以下のような利点を提供します。

  • 標準化されたテストインターフェース: *testing.T型を通じて、テストの失敗報告、ログ出力、並行テストの実行などの機能が提供されます。
  • 詳細なエラー報告: t.FailNow()t.Errorf()などのメソッドを使用することで、テストが失敗した際に、どのテストが、なぜ失敗したのかをより詳細に報告できるようになります。
  • go testコマンドとの統合: testingパッケージに準拠したテスト関数は、Goのビルドシステムに組み込まれたgo testコマンドによって自動的に発見・実行され、テスト結果が統一された形式で表示されます。

このコミットは、arrayパッケージのテストをこの新しい標準に準拠させるためのものであり、Go言語全体のテストインフラストラクチャの成熟に向けた一歩と言えます。

前提知識の解説

Go言語のテストフレームワーク (testingパッケージ)

Go言語には、標準ライブラリとしてtestingパッケージが提供されており、これを用いてユニットテストやベンチマークテストを記述します。

  • テストファイルの命名規則: テストファイルは通常、テスト対象のソースファイルと同じディレクトリに配置され、ファイル名の末尾に_test.goを付けます(例: my_package.goに対するmy_package_test.go)。
  • テスト関数の命名規則: テスト関数はTestで始まり、その後に続く名前の最初の文字は大文字である必要があります(例: func TestMyFunction(t *testing.T))。
  • *testing.T: テスト関数は、*testing.T型の引数を一つだけ取ります。このtオブジェクトを通じて、テストの失敗を報告したり、ログを出力したり、テストのヘルパー関数を呼び出したりします。
    • t.Fail(): テストを失敗としてマークしますが、テスト関数の実行は継続します。
    • t.FailNow(): テストを失敗としてマークし、現在のテスト関数の実行を即座に停止します。
    • t.Error() / t.Errorf(): t.Fail()を呼び出した後、指定されたメッセージをログに出力します。
    • t.Fatal() / t.Fatalf(): t.FailNow()を呼び出した後、指定されたメッセージをログに出力します。
  • テストの実行: go testコマンドをプロジェクトのルートディレクトリまたはテストファイルのあるディレクトリで実行することで、テストが自動的に発見され、実行されます。

container/arrayパッケージ

Go言語の初期の標準ライブラリには、containerというパッケージ群があり、その中にarrayパッケージが含まれていました。これは、動的な配列(可変長配列)の基本的な機能を提供するものでした。現在のGo言語では、組み込みのスライス型([]T)が非常に強力で柔軟であるため、このような独立したarrayパッケージは通常使用されません。このコミットは、Go言語の進化の過程で、組み込み型がより洗練される前の段階のコードベースを反映しています。

技術的詳細

このコミットの技術的な変更点は、主に以下の2点です。

  1. テスト関数のシグネチャ変更:

    • 変更前: export func TestInit() bool のように、ブール値を返す関数でした。trueがテスト成功、falseがテスト失敗を示していました。
    • 変更後: export func TestInit(t *testing.T) のように、*testing.T型の引数を受け取る関数になりました。これはGoの標準的なテスト関数のシグネチャです。
  2. テスト失敗の報告方法の変更:

    • 変更前: if condition { return false } のように、条件が満たされない場合にfalseを返してテスト失敗を報告していました。
    • 変更後: if condition { t.FailNow() } のように、*testing.TオブジェクトのFailNow()メソッドを呼び出してテスト失敗を報告しています。FailNow()は、現在のテスト関数の実行を即座に停止させるため、return falseと同様に、それ以降のテストロジックが実行されるのを防ぎます。
  3. 新しいパッケージのインポート:

    • import "testing": 新しいテストフレームワークを使用するために必須です。
    • import "sort": このコミットの差分にはsortパッケージのインポートも含まれていますが、実際のコード変更ではsortパッケージが直接使用されている箇所は見当たりません。これは、おそらく将来的なテストの追加や、以前のコミットで削除されたコードの名残である可能性があります。

これらの変更により、testarray.go内のテストは、go testコマンドによって適切に実行され、テスト結果が標準的な形式で報告されるようになります。

コアとなるコードの変更箇所

src/lib/container/array/testarray.go

--- a/src/lib/container/array/testarray.go
+++ b/src/lib/container/array/testarray.go
@@ -5,21 +5,21 @@
 package array
 
 import "array"
+import "testing"
+import "sort"
 
-export func TestInit() bool {
+export func TestInit(t *testing.T) {
 	var a array.Array;
-	if a.Init(0).Len() != 0 { return false }
-	if a.Init(1).Len() != 1 { return false }
-	if a.Init(10).Len() != 10 { return false }
-	return true;
+	if a.Init(0).Len() != 0 { t.FailNow() }
+	if a.Init(1).Len() != 1 { t.FailNow() }
+	if a.Init(10).Len() != 10 { t.FailNow() }
 }
 
 
-export func TestNew() bool {
-	if array.New(0).Len() != 0 { return false }
-	if array.New(1).Len() != 1 { return false }
-	if array.New(10).Len() != 10 { return false }
-	return true;
+export func TestNew(t *testing.T) {
+	if array.New(0).Len() != 0 { t.FailNow() }
+	if array.New(1).Len() != 1 { t.FailNow() }
+	if array.New(10).Len() != 10 { t.FailNow() }
 }
 
 
@@ -28,7 +28,7 @@ export func Val(i int) int {
 }
 
 
-export func TestAccess() bool {
+export func TestAccess(t *testing.T) {
 	const n = 100;
 	var a array.Array;
 	a.Init(n);
@@ -36,35 +36,34 @@ export func TestAccess() bool {
 		a.Set(i, Val(i));
 	}
 	for i := 0; i < n; i++ {
-		if a.At(i).(int) != Val(i) { return false }
+		if a.At(i).(int) != Val(i) { t.FailNow() }
 	}
-	return true;
 }
 
 
-export func TestInsertRemoveClear() bool {
+export func TestInsertRemoveClear(t *testing.T) {
 	const n = 100;
 	a := array.New(0);
 
 	for i := 0; i < n; i++ {
-		if a.Len() != i { return false }
+		if a.Len() != i { t.FailNow() }
 		a.Insert(0, Val(i));
-		if a.Last().(int) != Val(0) { return false }
+		if a.Last().(int) != Val(0) { t.FailNow() }
 	}
 	for i := n-1; i >= 0; i-- {
-		if a.Last().(int) != Val(0) { return false }
-		if a.Remove(0).(int) != Val(i) { return false }
-		if a.Len() != i { return false }
+		if a.Last().(int) != Val(0) { t.FailNow() }
+		if a.Remove(0).(int) != Val(i) { t.FailNow() }
+		if a.Len() != i { t.FailNow() }
 	}
 
-	if a.Len() != 0 { return false }
+	if a.Len() != 0 { t.FailNow() }
 	for i := 0; i < n; i++ {
 		a.Push(Val(i));
-		if a.Len() != i+1 { return false }
-		if a.Last().(int) != Val(i) { return false }
+		if a.Len() != i+1 { t.FailNow() }
+		if a.Last().(int) != Val(i) { t.FailNow() }
 	}
 	a.Init(0);
-	if a.Len() != 0 { return false }
+	if a.Len() != 0 { t.FailNow() }
 
 	const m = 5;
 	for j := 0; j < m; j++ {
@@ -72,11 +71,9 @@ export func TestInsertRemoveClear() bool {
 		for i := 0; i < n; i++ {
 			x := Val(i);
 			a.Push(x);
-			if a.Pop().(int) != x { return false }
-			if a.Len() != j+1 { return false }
+			if a.Pop().(int) != x { t.FailNow() }
+			if a.Len() != j+1 { t.FailNow() }
 		}
 	}
-	if a.Len() != m { return false }
-
-	return true;
+	if a.Len() != m { t.FailNow() }
 }

コアとなるコードの解説

上記の差分は、src/lib/container/array/testarray.goファイルにおける主要な変更を示しています。

  1. import "testing"import "sort" の追加:

    • testingパッケージは、Goの標準テストフレームワークであり、テスト関数が*testing.T型の引数を受け取るために必要です。
    • sortパッケージの追加は、このコミットの直接的なコード変更では使用されていませんが、将来的なテストの要件や、以前のコードベースの名残である可能性があります。
  2. テスト関数のシグネチャ変更:

    • TestInit() boolTestInit(t *testing.T) に変更されています。これは、Goの標準テストフレームワークに準拠するための必須の変更です。他のTestNew, TestAccess, TestInsertRemoveClear関数も同様に変更されています。
  3. テスト失敗の報告ロジックの変更:

    • 変更前は、テスト条件が満たされない場合に return false を使用してテスト失敗を報告していました。
    • 変更後は、t.FailNow() を使用しています。t.FailNow() は、現在のテスト関数を即座に終了させ、テストを失敗としてマークします。これにより、テストランナーはテストの失敗を検出し、適切なエラーメッセージを表示できるようになります。

これらの変更は、Go言語のテストエコシステムが成熟していく過程で、テストコードがより標準的で堅牢な方法で記述されるようになったことを示しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント: testingパッケージに関する情報
  • Go言語のGitHubリポジトリ: コミット履歴とソースコードの差分
  • Go言語の歴史に関する記事やブログ: Go言語の初期開発段階におけるテストフレームワークの進化に関する情報