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

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

このコミットは、Go言語の標準ライブラリであるnetパッケージ内のテストファイル群に対して行われた変更を記録しています。具体的には、特定のオペレーティングシステム(OS)やアーキテクチャでテストがスキップされる際に、そのスキップ理由をテストログに出力するためのメッセージが追加されています。これにより、テスト実行時の可視性が向上し、なぜ特定のテストが実行されなかったのかを容易に把握できるようになります。

コミット

9442c4429a7fe18aba304f8d239c4ca10ab598ad

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

https://github.com/golang/go/commit/9442c4429a7fe18aba304f8d239c4ca10ab598ad

元コミット内容

net: add skip message to test

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

変更の背景

Go言語のテストフレームワークでは、特定の環境(OSやアーキテクチャ)に依存するテストや、その環境では実行が困難なテストをスキップする機能が提供されています。これまでの実装では、テストがスキップされた場合、単にテスト関数からreturnするだけで、なぜスキップされたのかという情報がログに出力されませんでした。

このコミットの背景には、テストの実行結果をより詳細に、かつ分かりやすくしたいという意図があります。特に、CI/CD環境や異なる開発環境でテストを実行する際に、テストがスキップされた事実だけでなく、その具体的な理由(例:「このテストはPlan 9では実行されません」)がログに明示されることで、デバッグや問題の特定が容易になります。これにより、テストの健全性を確認するプロセスが改善され、開発者がテスト結果をより正確に解釈できるようになります。

前提知識の解説

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

Go言語には、標準でtestingパッケージが用意されており、これを用いてユニットテストやベンチマークテストを記述します。テスト関数はTestで始まる名前を持ち、*testing.T型の引数を取ります。

  • *testing.T: テストの実行状態を管理し、テストの失敗を報告したり、ログを出力したりするためのメソッドを提供します。
  • t.Logf(...): テストの実行中にフォーマットされた文字列をログに出力するために使用されます。テストが成功しても失敗しても出力されます。
  • テストのスキップ: testingパッケージでは、t.Skip()t.Skipf()メソッドを使ってテストをスキップできます。しかし、このコミットが行われた時点では、単にreturnすることでテストをスキップするパターンも多く見られました。このコミットは、そのreturnによるスキップの際に、t.Logfを使ってスキップ理由を明示的に出力するように変更しています。

runtimeパッケージとruntime.GOOS, runtime.GOARCH

Go言語の標準ライブラリであるruntimeパッケージは、Goプログラムの実行環境に関する情報を提供します。

  • runtime.GOOS: プログラムが実行されているオペレーティングシステムの名前(例: "linux", "windows", "darwin", "plan9", "netbsd", "openbsd"など)を文字列で返します。
  • runtime.GOARCH: プログラムが実行されているプロセッサアーキテクチャの名前(例: "amd64", "arm", "alpha"など)を文字列で返します。

これらの変数は、クロスプラットフォーム開発において、特定のOSやアーキテクチャに依存するコードの挙動を制御したり、今回のケースのようにテストの実行条件を分岐させたりするために頻繁に利用されます。ネットワーク関連のテストは、OSのネットワークスタックの実装に大きく依存するため、runtime.GOOSによる条件分岐が特に重要になります。

netパッケージのテストの特性

Go言語のnetパッケージは、ネットワークI/Oプリミティブを提供し、TCP/IP、UDP、Unixドメインソケットなどのネットワークプログラミングを可能にします。ネットワーク関連のテストは、以下のような理由で特定の環境に依存することがよくあります。

  • OSのネットワークスタックの違い: 各OSは独自のネットワークスタック実装を持っており、ソケットの挙動、マルチキャストのサポート、タイムアウト処理などが異なる場合があります。
  • 権限の問題: 特定のポートへのバインドやRAWソケットの使用など、管理者権限が必要な操作が含まれる場合があります。
  • ネットワークインターフェースの存在: テストによっては、特定の種類のネットワークインターフェース(例: IPv6対応インターフェース)が存在することを前提とする場合があります。

これらの理由から、netパッケージのテストでは、runtime.GOOSruntime.GOARCHを用いて、テストの実行環境をチェックし、サポートされていない環境ではテストをスキップするロジックが組み込まれています。

技術的詳細

このコミットの技術的な核心は、既存のテストスキップロジックにt.Logfによるログ出力を追加することです。変更前は、以下のようなコードパターンが一般的でした。

func TestSomething(t *testing.T) {
    if runtime.GOOS == "plan9" {
        return // Plan 9ではテストをスキップ
    }
    // ... テスト本体 ...
}

この変更により、上記のパターンは以下のように修正されました。

func TestSomething(t *testing.T) {
    if runtime.GOOS == "plan9" {
        t.Logf("skipping test on %q", runtime.GOOS) // スキップ理由をログに出力
        return
    }
    // ... テスト本体 ...
}

または、switch文を使用している箇所では、

func TestMulticastListener(t *testing.T) {
    switch runtime.GOOS {
    case "netbsd", "openbsd", "plan9", "windows":
        t.Logf("skipping test on %q", runtime.GOOS)
        return
    case "linux":
        if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
            t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
            return
        }
    }
    // ... テスト本体 ...
}

この変更は、テストの機能的な挙動には影響を与えません。テストはこれまで通りスキップされます。しかし、テスト実行時の標準出力には、スキップされたテストの名前とともに、skipping test on "plan9"のようなメッセージが表示されるようになります。これにより、テストスイート全体の実行結果をレビューする際に、どのテストが、なぜスキップされたのかが一目でわかるようになり、テストの網羅性や環境依存の問題を把握する上で非常に役立ちます。

特に、netパッケージのような低レベルなネットワーク操作を扱うテストでは、OSやアーキテクチャ固有の挙動が多いため、このような明示的なスキップメッセージは開発者にとって貴重な情報となります。例えば、Plan 9やWindowsといった特定のOSでは、マルチキャストや特定のソケットオプションがサポートされていない、あるいは挙動が異なるためにテストがスキップされることがあります。また、Linux上のARMやAlphaといった特定のアーキテクチャでは、コンパイラやランタイムの制約、あるいはハードウェア固有の理由でテストがスキップされるケースも考えられます。これらの情報をログに残すことで、Go言語のクロスプラットフォーム対応の現状をより正確に把握できるようになります。

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

このコミットは、src/pkg/net/ディレクトリ以下の複数のテストファイルに同様の変更を加えています。以下に代表的な変更箇所をいくつか示します。

src/pkg/net/multicast_test.go

--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -47,9 +47,11 @@ var multicastListenerTests = []struct {
 func TestMulticastListener(t *testing.T) {
 	switch runtime.GOOS {
 	case "netbsd", "openbsd", "plan9", "windows":
+		t.Logf("skipping test on %q", runtime.GOOS)
 		return
 	case "linux":
 		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+			t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
 			return
 		}
 	}
@@ -86,6 +88,7 @@ func TestMulticastListener(t *testing.T) {
 func TestSimpleMulticastListener(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
+		t.Logf("skipping test on %q", runtime.GOOS)
 		return
 	}

src/pkg/net/parse_test.go

--- a/src/pkg/net/parse_test.go
+++ b/src/pkg/net/parse_test.go
@@ -13,7 +13,9 @@ import (
 
 func TestReadLine(t *testing.T) {
 	// /etc/services file does not exist on windows and Plan 9.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		t.Logf("skipping test on %q", runtime.GOOS)
 		return
 	}
 	filename := "/etc/services" // a nice big file

src/pkg/net/timeout_test.go

--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -57,7 +57,9 @@ func testTimeout(t *testing.T, net, addr string, readFrom bool) {
 }
 
 func TestTimeoutUDP(t *testing.T) {
-	if runtime.GOOS == "plan9" {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Logf("skipping test on %q", runtime.GOOS)
 		return
 	}

コアとなるコードの解説

上記の変更箇所に見られるように、各テスト関数内でruntime.GOOSruntime.GOARCHをチェックし、特定の環境であればテストをスキップする既存のロジックに、t.Logf("skipping test on %q", runtime.GOOS)またはt.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)という行が追加されています。

  • t.Logf("skipping test on %q", runtime.GOOS):

    • t.Logfは、テストのログにメッセージを出力するための関数です。
    • "skipping test on %q"はフォーマット文字列で、%qは文字列をクォートして出力するための動詞です。これにより、OS名が引用符で囲まれて表示され、視認性が向上します。
    • runtime.GOOSは、現在のOSの名前(例: "plan9", "windows")を返します。
    • この行が実行されると、例えばskipping test on "plan9"のようなメッセージがテストログに出力されます。
  • t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH):

    • こちらは、OSとアーキテクチャの両方を指定してスキップする場合に使用されます。
    • runtime.GOARCHは、現在のアーキテクチャの名前(例: "arm", "alpha")を返します。
    • この行が実行されると、例えばskipping test on "linux"/"arm"のようなメッセージがテストログに出力されます。

これらの変更は、テストがスキップされるたびに、その理由がテスト実行ログに明示的に記録されることを保証します。これにより、テストスイートの実行結果を分析する際に、どのテストがどの環境でスキップされたのかを簡単に追跡できるようになり、テストのデバッグやクロスプラットフォーム互換性の問題特定に役立ちます。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (testingおよびruntimeパッケージ)
  • Go言語のソースコード (特にnetパッケージのテストファイル)
  • Gitのコミットログと差分表示
  • GitHubのコミットページ
  • 一般的なGo言語のテストプラクティスに関する知識