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

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

このコミットは、Go言語のテストインフラストラクチャにおける重要な改善を導入しています。具体的には、テストファイル内で特定のテストをスキップするための新しいディレクティブ // skip を導入し、既存のテストファイルの一部をこの新しい形式に移行しています。これにより、テストの管理と実行がより明確かつ効率的になります。

コミット

commit e2662835b8dd3ca4aa69997afe3774467a677df8
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Thu Mar 22 02:14:44 2012 +0800

    test: use testlib in a few more cases
            Introduce a new skip cmd.
    
    R=golang-dev, bradfitz, iant, iant
    CC=golang-dev
    https://golang.org/cl/5868048

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

https://github.com/golang/go/commit/e2662835b8dd3ca4aa69997afe3774467a677df8

元コミット内容

test: use testlib in a few more cases
        Introduce a new skip cmd.

R=golang-dev, bradfitz, iant, iant
CC=golang-dev
https://golang.org/cl/5868048

変更の背景

Go言語のテストスイートは、コンパイラ、ランタイム、標準ライブラリの正確性を保証するために非常に広範です。初期のGoのテストフレームワークでは、テストファイルの先頭にコメント形式でテストの期待される動作や実行方法を記述する慣習がありました。例えば、// true はテストが成功することを期待することを示し、複雑なシェルコマンドが記述されることもありました。

しかし、このような記述方法は、テストの意図を明確にする上で曖昧さを含んだり、テストランナーが解釈するロジックが複雑になったりする可能性がありました。特に、特定の条件下でテストをスキップしたい場合、そのための明確なメカニズムが不足していました。

このコミットの背景には、テストインフラストラクチャをより堅牢で、理解しやすく、保守しやすいものにするという目的があります。// skip コマンドの導入は、テストの実行を明示的に制御し、テストランナーが不要なテストを実行しないようにするための、よりクリーンな方法を提供します。これにより、テストスイート全体の実行時間を短縮し、開発者がテストの意図をより迅速に把握できるようになります。

また、test/fixedbugs/bug223.go の変更に見られるように、以前はシェルコマンドで表現されていたエラーチェックのロジックが // errorcheck および // ERROR ディレクティブに置き換えられています。これは、テストの期待値をGoのテストフレームワーク内でより直接的に表現する方向への移行を示しており、テストの可読性と移植性を向上させる狙いがあります。

前提知識の解説

このコミットを理解するためには、以下のGo言語のテストに関する基本的な知識が必要です。

  • Go言語のテストフレームワーク: Go言語は標準で testing パッケージを提供しており、go test コマンドを通じてテストを実行します。しかし、このコミットが対象としているのは、Goプロジェクト自体のコンパイラやランタイムのテストであり、これらは testing パッケージとは異なる、より低レベルなカスタムテストハーネス (test/run.go など) を使用しています。
  • test/run.go: これはGo言語のソースコードリポジトリ内のカスタムテストランナーです。Goのコンパイラやランタイムのテストは、通常の go test コマンドでは実行できない特殊なケースが多く、この run.go がそれらのテストをオーケストレーションする役割を担っています。テストファイルの先頭に記述された特殊なコメント(ディレクティブ)を解釈し、それに基づいてテストのコンパイル、ビルド、実行、または特定のチェックを行います。
  • test/testlib: これはシェルスクリプトのライブラリであり、test/run.go がテストを実行する際に利用するヘルパー関数や環境設定を提供します。例えば、コンパイルや実行の際に共通して使用されるパスやフラグなどが定義されています。
  • テストディレクティブ: Goのテストファイル(特にコンパイラやランタイムのテスト)の先頭には、// で始まる特殊なコメントが記述されることがあります。これらはテストランナー (test/run.go) に対する指示であり、テストの実行方法や期待される結果を定義します。例えば、// true はテストが成功することを期待し、// errorcheck はコンパイルエラーをチェックすることを示します。

技術的詳細

このコミットの技術的な核心は、test/run.gotest/testlib の変更、そして既存のテストファイルへの新しい // skip ディレクティブの適用にあります。

  1. test/run.go の変更:

    • test 構造体に action フィールドがあり、これがテストの実行アクション("compile", "build", "run", "errorcheck" など)を決定します。このコミットでは、この action フィールドが取りうる値に "skip" が追加されました。
    • run() 関数内のロジックが更新され、テストファイルの先頭から読み取られたディレクティブが "skip" であった場合、t.action"skip" に設定し、即座に return するようになりました。これにより、// skip とマークされたテストは、それ以降のコンパイルや実行のステップに進むことなく、テストランナーによってスキップされます。
    • test/run.go 自体の先頭のディレクティブも // #ignore から // skip に変更されています。これは、run.go 自体がテストとして実行されるべきではないことを示唆しています。
  2. test/testlib の変更:

    • skip() という新しいシェル関数が追加されました。この関数は単に true を返します。これは、test/run.goskip アクションを処理する際に、testlib 内で対応するコマンドが存在することを保証するためのプレースホルダー、または将来的な拡張のための準備と考えられます。
  3. 既存テストファイルの変更:

    • 多くのテストファイル(例: test/cmplxdivide.c, test/cmplxdivide1.go, test/ddd2.go など)の先頭のディレクティブが、// true やその他の複雑なシェルコマンドから // skip に変更されました。これは、これらのテストが特定の条件下で実行される必要がない、あるいは一時的に無効化されていることを示します。
    • 特筆すべきは test/fixedbugs/bug223.go の変更です。このファイルでは、以前は // (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223 という複雑なシェルコマンドが記述されていました。これは、コンパイル時に「initialization loop」というエラーメッセージが出力されることを期待するものでした。このコミットでは、これが // errorcheck// ERROR "initialization loop" に変更されています。
      • // errorcheck は、テストランナーに対して、このファイルがコンパイルエラーをチェックするためのものであることを指示します。
      • // ERROR "initialization loop" は、その行で指定された正規表現に一致するエラーメッセージがコンパイラから出力されることを期待することを示します。 この変更は、テストの期待値をシェルコマンドに依存するのではなく、Goのテストフレームワーク内でより宣言的に表現する方向への移行を明確に示しています。これにより、テストの可読性が向上し、異なる環境でのテスト実行の信頼性が高まります。

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

test/run.go

--- a/test/run.go
+++ b/test/run.go
@@ -1,4 +1,4 @@
-// #ignore
+// skip
 
 // Copyright 2012 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -172,7 +172,7 @@ type test struct {
 	donec       chan bool // closed when done
 
 	src    string
-	action string // "compile", "build", "run", "errorcheck"
+	action string // "compile", "build", "run", "errorcheck", "skip"
 
 	tempDir string
 	err     error
@@ -253,6 +253,9 @@ func (t *test) run() {
 		fallthrough
 	case "compile", "build", "run", "errorcheck":
 		t.action = action
+	case "skip":
+		t.action = "skip"
+		return
 	default:
 		t.err = skipError("skipped; unknown pattern: " + action)
 		t.action = "??"

test/testlib

--- a/test/testlib
+++ b/test/testlib
@@ -38,3 +38,7 @@ cmpout() {
 errorcheck() {
 	errchk $G -e $D/$F.go
 }
+
+skip() {
+	true
+}

test/fixedbugs/bug223.go

--- a/test/fixedbugs/bug223.go
+++ b/test/fixedbugs/bug223.go
@@ -1,4 +1,4 @@
-// (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223
+// errorcheck
 
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -18,4 +18,4 @@ func f() {
 	}
 }
 
-var m = map[string]F{"f": f}
+var m = map[string]F{"f": f} // ERROR "initialization loop"

コアとなるコードの解説

test/run.go の変更点

  1. test 構造体の action フィールド: action string // "compile", "build", "run", "errorcheck", "skip" この行は、test 構造体の action フィールドが取りうる値に "skip" が追加されたことを示しています。これは、テストランナーがテストを「スキップ」するという新しい動作を認識できるようになったことを意味します。

  2. run() メソッド内の case "skip":

    case "skip":
        t.action = "skip"
        return
    

    これは、test/run.go の中核的な変更です。テストファイルの先頭に // skip ディレクティブが検出された場合、run() メソッドはこの case "skip" ブロックに入ります。

    • t.action = "skip": 現在のテストの実行アクションを "skip" に設定します。
    • return: これが最も重要です。この return ステートメントにより、テストのコンパイル、ビルド、実行、エラーチェックなどの後続の処理が一切行われずに、run() メソッドが即座に終了します。これにより、// skip とマークされたテストは効率的にスキップされます。
  3. ファイル先頭のディレクティブ変更: // #ignore から // skip への変更は、test/run.go 自体がテストとして実行されるべきではないことを、新しいより明確な skip ディレクティブで表現しています。

test/testlib の変更点

skip() {
	true
}

testlibskip() という新しいシェル関数が追加されました。この関数は単に true を返します。これは、test/run.goskip アクションを処理する際に、testlib 内で対応するコマンドが存在することを保証するためのものです。Goのテストハーネスは、テストディレクティブに対応するシェル関数を testlib から呼び出すことがあるため、この定義は互換性や将来的な拡張のために重要です。

test/fixedbugs/bug223.go の変更点

- // (! $G $D/$F.go) | grep 'initialization loop' >/dev/null || echo BUG: bug223
+ // errorcheck
...
- var m = map[string]F{"f": f}
+ var m = map[string]F{"f": f} // ERROR "initialization loop"

この変更は、テストの期待値の表現方法が改善されたことを示しています。

  • 以前の行は、シェルコマンドを使用して、コンパイラが「initialization loop」という文字列を含むエラーを出力するかどうかをチェックしていました。これは外部コマンド (grep) に依存し、プラットフォーム間の互換性やエラーメッセージの厳密なマッチングに課題がありました。
  • 新しい // errorcheck ディレクティブは、このファイルがコンパイルエラーをチェックするためのものであることを test/run.go に直接伝えます。
  • // ERROR "initialization loop" は、特定のコード行で期待されるエラーメッセージの正規表現パターンを直接指定します。これにより、テストランナーはコンパイラの出力とこのパターンを比較し、より正確かつGoのテストフレームワーク内で完結した形でエラーチェックを実行できます。これは、テストの堅牢性と可読性を大幅に向上させます。

これらの変更により、Goのテストインフラストラクチャは、テストのスキップをより明示的に行えるようになり、またエラーチェックのメカニズムもよりGoネイティブで宣言的な方法に進化しました。

関連リンク

  • Go言語の公式リポジトリ: https://github.com/golang/go
  • Gerrit Change-Id: 5868048 (Goプロジェクトのコードレビューシステム)

参考にした情報源リンク

  • Go言語のテストに関する公式ドキュメント (当時のものに直接アクセスすることは難しいですが、現在のドキュメントも参考になります): https://go.dev/doc/code#testing
  • Go言語のソースコード内の test ディレクトリの構造と慣習 (コミット当時の状況を推測する上で重要): https://github.com/golang/go/tree/master/test
  • Go言語のGerritコードレビューシステム: https://go-review.googlesource.com/ (コミットメッセージに記載されているCL番号 5868048 で検索可能)