[インデックス 14979] ファイルの概要
コミット
all: use t.Skip{,f}
Replace various t.Log{,f} ; return checks with t.Skip{,f}.
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6a9e956f194a4b22beb052fb2152f6f395d45158
元コミット内容
commit 6a9e956f194a4b22beb052fb2152f6f395d45158
Author: Dave Cheney <dave@cheney.net>
Date: Thu Jan 24 17:32:10 2013 +1100
all: use t.Skip{,f}
Replace various t.Log{,f} ; return checks with t.Skip{,f}.
R=golang-dev, n13m3y3r, bradfitz, adg, mikioh.mikioh
CC=golang-dev
https://golang.org/cl/7193044
変更の背景
このコミットは、Go言語の標準ライブラリ内のテストコードにおいて、テストをスキップする際の慣用的なパターンを改善することを目的としています。以前は、特定の条件(例: testing.Short()
フラグが設定されている場合、特定のOSでの実行、外部ネットワークへのアクセスが必要な場合など)でテストを実行しないようにするために、t.Log
または t.Logf
でスキップ理由を出力し、その後に return
で関数を終了させるという手法が広く用いられていました。
しかし、このパターンにはいくつかの問題がありました。
- 意図の不明瞭さ:
t.Log
とreturn
の組み合わせは、テストがスキップされたのか、それとも単にログを出力して早期終了しただけなのか、コードを読んだだけでは直感的に理解しにくい場合がありました。 - テストランナーとの連携: Goのテストフレームワークは、
t.Skip
やt.Skipf
を呼び出すことで、テストがスキップされたことを明示的に認識し、適切なレポートを生成します。t.Log
とreturn
の組み合わせでは、テストランナーはテストが正常に完了したか、あるいは失敗したと誤解する可能性がありました。これにより、テスト結果の集計やCI/CDパイプラインでの処理において、正確な情報が得られないことがありました。 - 冗長性:
t.Log
とreturn
の2行を記述する必要があり、コードが冗長になる傾向がありました。
このコミットは、これらの問題を解決するために、テストをスキップする際には常に t.Skip
または t.Skipf
を使用するように統一することを目的としています。これにより、テストコードの可読性が向上し、テスト結果の報告がより正確になり、Goのテストフレームワークの意図に沿った利用が促進されます。
前提知識の解説
Go言語の testing
パッケージ
Go言語には、ユニットテストやベンチマークテストを記述するための標準パッケージ testing
が用意されています。テストファイルは通常、テスト対象のGoファイルと同じディレクトリに _test.go
というサフィックスを付けて配置されます。
*testing.T
テスト関数は func TestXxx(t *testing.T)
の形式で定義され、*testing.T
型の引数 t
を受け取ります。この t
オブジェクトは、テストの実行中に様々な操作を行うためのメソッドを提供します。
t.Log
と t.Logf
t.Log
および t.Logf
は、テストの実行中に情報をログに出力するために使用されます。t.Logf
は fmt.Printf
と同様にフォーマット文字列と引数を受け取ります。これらの関数は、テストの成功・失敗に関わらず情報を出力する際に便利ですが、テストの実行フローを制御するものではありません。
t.Skip
と t.Skipf
t.Skip
および t.Skipf
は、現在のテストをスキップするために使用されます。これらの関数が呼び出されると、テストの実行は直ちに停止し、テストランナーは当該テストがスキップされたものとして扱います。t.Skipf
は t.Logf
と同様にフォーマット文字列と引数を受け取り、スキップ理由を詳細に記述できます。
t.Skip
や t.Skipf
を使用する主なシナリオは以下の通りです。
- 環境依存のテスト: 特定のオペレーティングシステム、アーキテクチャ、または外部サービスが利用できない場合にテストをスキップする。
- リソース依存のテスト: データベース接続、ネットワークアクセス、特定のファイルパスなど、テストに必要なリソースが利用できない場合にスキップする。
- 時間のかかるテスト:
go test -short
フラグが指定された場合に、実行に時間がかかるテストをスキップする。これはCI/CD環境での高速なフィードバックループを可能にするためによく利用されます。 - 未実装の機能のテスト: まだ実装されていない機能に対するテストを一時的にスキップする。
testing.Short()
testing
パッケージには Short()
関数があり、これは go test -short
コマンドラインフラグが設定されている場合に true
を返します。開発者がテストを高速に実行したい場合に、時間のかかるテストをスキップするためにこの関数がよく利用されます。
技術的詳細
このコミットの技術的な核心は、Goのテストフレームワークにおけるテストスキップのセマンティクスを統一し、より堅牢で意図が明確なテストコードを促進することにあります。
従来の t.Log{,f}; return
パターンは、テストの実行を中断するという点では t.Skip{,f}
と同じ効果をもたらしますが、テストランナーに対するシグナルが異なります。
t.Log{,f}; return
: テストランナーは、テスト関数が正常に終了したと解釈します。ログメッセージは出力されますが、テストが「スキップされた」という特別なステータスとしては認識されません。これは、テスト結果の集計ツールやCI/CDシステムが、スキップされたテストを誤って成功したテストとしてカウントしたり、あるいは単に実行されなかったテストとして扱ったりする原因となる可能性があります。t.Skip{,f}
: この関数が呼び出されると、testing
パッケージは内部的にruntime.Goexit()
を呼び出し、現在のゴルーチン(テスト関数)を終了させます。同時に、テストランナーに対して、このテストが意図的にスキップされたことを明示的に通知します。これにより、テスト結果のレポートには「スキップされたテスト」として正確に表示され、テストスイート全体の健全性をより正確に把握できるようになります。
この変更は、Goのテストフレームワークの設計思想、すなわち「テストは明確な結果(成功、失敗、スキップ)を報告すべきである」という原則に合致しています。特に、大規模なプロジェクトやCI/CD環境では、テスト結果の正確な集計と可視化が非常に重要になります。t.Skip{,f}
の使用を徹底することで、テストのステータスが曖昧になることを防ぎ、テストレポートの信頼性を高めることができます。
また、t.Skipf
の導入により、スキップ理由をフォーマット文字列で記述できるようになり、より詳細で分かりやすいメッセージを提供することが可能になりました。これは、テストがスキップされた原因をデバッグする際に役立ちます。
このコミットは、Goの標準ライブラリ全体にわたる広範な変更であり、多くのテストファイルに影響を与えています。これは、Goコミュニティがコードの品質と一貫性を重視していることの表れでもあります。
コアとなるコードの変更箇所
このコミットでは、Goの標準ライブラリ内の多数のテストファイルで、t.Log{,f}
と return
の組み合わせが t.Skip{,f}
に置き換えられています。以下に、代表的な変更例をいくつか示します。
src/pkg/archive/zip/zip_test.go
--- a/src/pkg/archive/zip/zip_test.go
+++ b/src/pkg/archive/zip/zip_test.go
@@ -18,8 +18,7 @@ import (
func TestOver65kFiles(t *testing.T) {
if testing.Short() {
- t.Logf("slow test; skipping")
- return
+ t.Skip("slow test; skipping")
}
buf := new(bytes.Buffer)
w := NewWriter(buf)
ここでは、testing.Short()
が true
の場合に、t.Logf("slow test; skipping")
と return
でスキップしていた箇所が、t.Skip("slow test; skipping")
の1行に置き換えられています。
src/pkg/crypto/x509/verify_test.go
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -309,8 +309,7 @@ func TestGoVerify(t *testing.T) {
func TestSystemVerify(t *testing.T) {
if runtime.GOOS != "windows" {
- t.Logf("skipping verify test using system APIs on %q", runtime.GOOS)
- return
+ t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
}
testVerify(t, true)
ここでは、runtime.GOOS
が "windows" でない場合に、特定のOSに依存するテストをスキップするために t.Logf
と return
を使用していた箇所が、t.Skipf
に変更されています。t.Skipf
を使うことで、スキップ理由にOS名を埋め込むことができます。
src/pkg/log/syslog/syslog_test.go
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -41,23 +41,14 @@ func startServer(done chan<- string) {
go runSyslog(c, done)
}
-func skipNetTest(t *testing.T) bool {
- if testing.Short() {
- // Depends on syslog daemon running, and sometimes it's not.
- t.Logf("skipping syslog test during -short")
- return true
- }
- return false
-}
-
func TestNew(t *testing.T) {
if LOG_LOCAL7 != 23<<3 {
t.Fatalf("LOG_LOCAL7 has wrong value")
}
- if skipNetTest(t) {
- return
+ if testing.Short() {
+ // Depends on syslog daemon running, and sometimes it's not.
+ t.Skip("skipping syslog test during -short")
}
-
s, err := New(LOG_INFO|LOG_USER, "")
if err != nil {
t.Fatalf("New() failed: %s", err)
この例では、skipNetTest
というヘルパー関数が削除され、そのロジックが直接テスト関数内にインライン化されています。そして、その中で t.Logf
と return
の代わりに t.Skip
が使われています。これにより、テストスキップのロジックがより直接的になり、ヘルパー関数を呼び出すオーバーヘッドもなくなります。
コアとなるコードの解説
上記の変更箇所は、すべて同じパターンに従っています。
- 条件判定:
if
文でテストをスキップすべき条件(例:testing.Short()
,runtime.GOOS != "windows"
,os.Getuid() != 0
など)を判定します。 - ログ出力と早期終了の置き換え: 従来の
t.Log("reason"); return
またはt.Logf("reason %v", arg); return
の2行が、t.Skip("reason")
またはt.Skipf("reason %v", arg)
の1行に置き換えられています。
この変更の意図は、Goのテストフレームワークが提供する t.Skip
および t.Skipf
メソッドを、テストをスキップする際の標準的かつ推奨される方法として一貫して使用することです。
- 明確な意図:
t.Skip
を使用することで、コードを読む開発者に対して「このテストは意図的にスキップされた」という明確なシグナルを送ります。これにより、テストが失敗したのか、それとも単に実行されなかったのかといった混乱を防ぎます。 - 正確なテストレポート:
go test
コマンドやCI/CDツールは、t.Skip
が呼び出されたテストを「スキップされた」として正確に報告します。これにより、テストスイート全体の健全性に関するより正確な統計情報が得られます。例えば、go test -v
を実行すると、スキップされたテストは--- SKIP: TestName (duration)
のように表示されます。 - 簡潔なコード:
t.Log
とreturn
の2行がt.Skip
の1行に集約されることで、コードの行数が減り、より簡潔になります。
このコミットは、Goの標準ライブラリのテストコードベース全体にわたる品質向上と一貫性の確立に貢献しています。これは、Go言語の設計哲学である「シンプルさ」と「明瞭さ」をテストコードにも適用しようとする試みの一環と言えます。
関連リンク
- Go CL 7193044: https://golang.org/cl/7193044
参考にした情報源リンク
- Go testing package documentation: https://pkg.go.dev/testing
- Go blog post about testing: https://go.dev/blog/testing
- Stack Overflow discussions on
t.Skip
vst.Log
+return
(general understanding, no specific link referenced for this commit, but common knowledge in Go community) - Go source code for
testing
package (for understandingt.Skip
implementation details)
# [インデックス 14979] ファイルの概要
## コミット
all: use t.Skip{,f}
Replace various t.Log{,f} ; return checks with t.Skip{,f}.
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/6a9e956f194a4b22beb052fb2152f6f395d45158](https://github.com/golang/go/commit/6a9e956f194a4b22beb052fb2152f6f395d45158)
## 元コミット内容
commit 6a9e956f194a4b22beb052fb2152f6f395d45158 Author: Dave Cheney dave@cheney.net Date: Thu Jan 24 17:32:10 2013 +1100
all: use t.Skip{,f}
Replace various t.Log{,f} ; return checks with t.Skip{,f}.
R=golang-dev, n13m3y3r, bradfitz, adg, mikioh.mikioh
CC=golang-dev
https://golang.org/cl/7193044
## 変更の背景
このコミットは、Go言語の標準ライブラリ内のテストコードにおいて、テストをスキップする際の慣用的なパターンを改善することを目的としています。以前は、特定の条件(例: `testing.Short()` フラグが設定されている場合、特定のOSでの実行、外部ネットワークへのアクセスが必要な場合など)でテストを実行しないようにするために、`t.Log` または `t.Logf` でスキップ理由を出力し、その後に `return` で関数を終了させるという手法が広く用いられていました。
しかし、このパターンにはいくつかの問題がありました。
1. **意図の不明瞭さ**: `t.Log` と `return` の組み合わせは、テストがスキップされたのか、それとも単にログを出力して早期終了しただけなのか、コードを読んだだけでは直感的に理解しにくい場合がありました。
2. **テストランナーとの連携**: Goのテストフレームワークは、`t.Skip` や `t.Skipf` を呼び出すことで、テストがスキップされたことを明示的に認識し、適切なレポートを生成します。`t.Log` と `return` の組み合わせでは、テストランナーはテストが正常に完了したか、あるいは失敗したと誤解する可能性がありました。これにより、テスト結果の集計やCI/CDパイプラインでの処理において、正確な情報が得られないことがありました。
3. **冗長性**: `t.Log` と `return` の2行を記述する必要があり、コードが冗長になる傾向がありました。
このコミットは、これらの問題を解決するために、テストをスキップする際には常に `t.Skip` または `t.Skipf` を使用するように統一することを目的としています。これにより、テストコードの可読性が向上し、テスト結果の報告がより正確になり、Goのテストフレームワークの意図に沿った利用が促進されます。
## 前提知識の解説
### Go言語の `testing` パッケージ
Go言語には、ユニットテストやベンチマークテストを記述するための標準パッケージ `testing` が用意されています。テストファイルは通常、テスト対象のGoファイルと同じディレクトリに `_test.go` というサフィックスを付けて配置されます。
### `*testing.T`
テスト関数は `func TestXxx(t *testing.T)` の形式で定義され、`*testing.T` 型の引数 `t` を受け取ります。この `t` オブジェクトは、テストの実行中に様々な操作を行うためのメソッドを提供します。
### `t.Log` と `t.Logf`
`t.Log` および `t.Logf` は、テストの実行中に情報をログに出力するために使用されます。`t.Logf` は `fmt.Printf` と同様にフォーマット文字列と引数を受け取ります。これらの関数は、テストの成功・失敗に関わらず情報を出力する際に便利ですが、テストの実行フローを制御するものではありません。
### `t.Skip` と `t.Skipf`
`t.Skip` および `t.Skipf` は、現在のテストをスキップするために使用されます。これらの関数が呼び出されると、テストの実行は直ちに停止し、テストランナーは当該テストがスキップされたものとして扱います。`t.Skipf` は `t.Logf` と同様にフォーマット文字列と引数を受け取り、スキップ理由を詳細に記述できます。
`t.Skip` や `t.Skipf` を使用する主なシナリオは以下の通りです。
* **環境依存のテスト**: 特定のオペレーティングシステム、アーキテクチャ、または外部サービスが利用できない場合にテストをスキップする。
* **リソース依存のテスト**: データベース接続、ネットワークアクセス、特定のファイルパスなど、テストに必要なリソースが利用できない場合にスキップする。
* **時間のかかるテスト**: `go test -short` フラグが指定された場合に、実行に時間がかかるテストをスキップする。これはCI/CD環境での高速なフィードバックループを可能にするためによく利用されます。
* **未実装の機能のテスト**: まだ実装されていない機能に対するテストを一時的にスキップする。
### `testing.Short()`
`testing` パッケージには `Short()` 関数があり、これは `go test -short` コマンドラインフラグが設定されている場合に `true` を返します。開発者がテストを高速に実行したい場合に、時間のかかるテストをスキップするためにこの関数がよく利用されます。
## 技術的詳細
このコミットの技術的な核心は、Goのテストフレームワークにおけるテストスキップのセマンティクスを統一し、より堅牢で意図が明確なテストコードを促進することにあります。
従来の `t.Log{,f}; return` パターンは、テストの実行を中断するという点では `t.Skip{,f}` と同じ効果をもたらしますが、テストランナーに対するシグナルが異なります。
* `t.Log{,f}; return`: テストランナーは、テスト関数が正常に終了したと解釈します。ログメッセージは出力されますが、テストが「スキップされた」という特別なステータスとしては認識されません。これは、テスト結果の集計ツールやCI/CDシステムが、スキップされたテストを誤って成功したテストとしてカウントしたり、あるいは単に実行されなかったテストとして扱ったりする原因となる可能性があります。
* `t.Skip{,f}`: この関数が呼び出されると、`testing` パッケージは内部的に `runtime.Goexit()` を呼び出し、現在のゴルーチン(テスト関数)を終了させます。同時に、テストランナーに対して、このテストが意図的にスキップされたことを明示的に通知します。これにより、テスト結果のレポートには「スキップされたテスト」として正確に表示され、テストスイート全体の健全性をより正確に把握できるようになります。
この変更は、Goのテストフレームワークの設計思想、すなわち「テストは明確な結果(成功、失敗、スキップ)を報告すべきである」という原則に合致しています。特に、大規模なプロジェクトやCI/CD環境では、テスト結果の正確な集計と可視化が非常に重要になります。`t.Skip{,f}` の使用を徹底することで、テストのステータスが曖昧になることを防ぎ、テストレポートの信頼性を高めることができます。
また、`t.Skipf` の導入により、スキップ理由をフォーマット文字列で記述できるようになり、より詳細で分かりやすいメッセージを提供することが可能になりました。これは、テストがスキップされた原因をデバッグする際に役立ちます。
このコミットは、Goの標準ライブラリ全体にわたる広範な変更であり、多くのテストファイルに影響を与えています。これは、Goコミュニティがコードの品質と一貫性を重視していることの表れでもあります。
## コアとなるコードの変更箇所
このコミットでは、Goの標準ライブラリ内の多数のテストファイルで、`t.Log{,f}` と `return` の組み合わせが `t.Skip{,f}` に置き換えられています。以下に、代表的な変更例をいくつか示します。
### `src/pkg/archive/zip/zip_test.go`
```diff
--- a/src/pkg/archive/zip/zip_test.go
+++ b/src/pkg/archive/zip/zip_test.go
@@ -18,8 +18,7 @@ import (
func TestOver65kFiles(t *testing.T) {
if testing.Short() {
- t.Logf("slow test; skipping")
- return
+ t.Skip("slow test; skipping")
}
buf := new(bytes.Buffer)
w := NewWriter(buf)
ここでは、testing.Short()
が true
の場合に、t.Logf("slow test; skipping")
と return
でスキップしていた箇所が、t.Skip("slow test; skipping")
の1行に置き換えられています。
src/pkg/crypto/x509/verify_test.go
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -309,8 +309,7 @@ func TestGoVerify(t *testing.T) {
func TestSystemVerify(t *testing.T) {
if runtime.GOOS != "windows" {
- t.Logf("skipping verify test using system APIs on %q", runtime.GOOS)
- return
+ t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
}
testVerify(t, true)
ここでは、runtime.GOOS
が "windows" でない場合に、特定のOSに依存するテストをスキップするために t.Logf
と return
を使用していた箇所が、t.Skipf
に変更されています。t.Skipf
を使うことで、スキップ理由にOS名を埋め込むことができます。
src/pkg/log/syslog/syslog_test.go
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -41,23 +41,14 @@ func startServer(done chan<- string) {
go runSyslog(c, done)
}
-func skipNetTest(t *testing.T) bool {
- if testing.Short() {
- // Depends on syslog daemon running, and sometimes it's not.
- t.Logf("skipping syslog test during -short")
- return true
- }
- return false
-}
-
func TestNew(t *testing.T) {
if LOG_LOCAL7 != 23<<3 {
t.Fatalf("LOG_LOCAL7 has wrong value")
}
- if skipNetTest(t) {
- return
+ if testing.Short() {
+ // Depends on syslog daemon running, and sometimes it's not.
+ t.Skip("skipping syslog test during -short")
}
-
s, err := New(LOG_INFO|LOG_USER, "")
if err != nil {
t.Fatalf("New() failed: %s", err)
この例では、skipNetTest
というヘルパー関数が削除され、そのロジックが直接テスト関数内にインライン化されています。そして、その中で t.Logf
と return
の代わりに t.Skip
が使われています。これにより、テストスキップのロジックがより直接的になり、ヘルパー関数を呼び出すオーバーヘッドもなくなります。
コアとなるコードの解説
上記の変更箇所は、すべて同じパターンに従っています。
- 条件判定:
if
文でテストをスキップすべき条件(例:testing.Short()
,runtime.GOOS != "windows"
,os.Getuid() != 0
など)を判定します。 - ログ出力と早期終了の置き換え: 従来の
t.Log("reason"); return
またはt.Logf("reason %v", arg); return
の2行が、t.Skip("reason")
またはt.Skipf("reason %v", arg)
の1行に置き換えられています。
この変更の意図は、Goのテストフレームワークが提供する t.Skip
および t.Skipf
メソッドを、テストをスキップする際の標準的かつ推奨される方法として一貫して使用することです。
- 明確な意図:
t.Skip
を使用することで、コードを読む開発者に対して「このテストは意図的にスキップされた」という明確なシグナルを送ります。これにより、テストが失敗したのか、それとも単に実行されなかったのかといった混乱を防ぎます。 - 正確なテストレポート:
go test
コマンドやCI/CDツールは、t.Skip
が呼び出されたテストを「スキップされた」として正確に報告します。これにより、テストスイート全体の健全性に関するより正確な統計情報が得られます。例えば、go test -v
を実行すると、スキップされたテストは--- SKIP: TestName (duration)
のように表示されます。 - 簡潔なコード:
t.Log
とreturn
の2行がt.Skip
の1行に集約されることで、コードの行数が減り、より簡潔になります。
このコミットは、Goの標準ライブラリのテストコードベース全体にわたる品質向上と一貫性の確立に貢献しています。これは、Go言語の設計哲学である「シンプルさ」と「明瞭さ」をテストコードにも適用しようとする試みの一環と言えます。
関連リンク
- Go CL 7193044: https://golang.org/cl/7193044
参考にした情報源リンク
- Go testing package documentation: https://pkg.go.dev/testing
- Go blog post about testing: https://go.dev/blog/testing
- Stack Overflow discussions on
t.Skip
vst.Log
+return
(general understanding, no specific link referenced for this commit, but common knowledge in Go community) - Go source code for
testing
package (for understandingt.Skip
implementation details)