[インデックス 19568] ファイルの概要
このコミットは、Go言語の標準ライブラリであるtestingパッケージにおけるテストおよびExampleの実行時間表示形式の不整合を修正するものです。具体的には、時間の表示形式を統一し、より機械的に解析しやすい形式に改善しています。
コミット
commit 0e92b538a9f6e337b8e48f47f38803e8245c03cc
Author: Robert Dinu <r@varp.se>
Date: Wed Jun 18 10:59:25 2014 -0700
testing: fix timing format inconsistency
Fixes #8175.
LGTM=r
R=golang-codereviews, r, gobot
CC=golang-codereviews
https://golang.org/cl/103320043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0e92b538a9f6e337b8e48f47f38803e8245c03cc
元コミット内容
このコミットは、Goのtestingパッケージにおける時間表示形式の不整合を修正することを目的としています。具体的には、Issue #8175で報告された問題を解決します。
変更の背景
Goのtestingパッケージは、ユニットテストやExampleの実行結果を表示する際に、テストやExampleの実行にかかった時間を表示します。しかし、この時間の表示形式が、テストとExampleの間で一貫性がなく、また、場合によっては人間が読みやすい形式(例: 1m30s)と、より厳密な数値形式(例: 90.00s)が混在していました。
このような不整合は、特にテスト結果を自動的に解析するツールやスクリプトにとって問題となります。形式が一定でないと、正確な時間情報を抽出することが困難になるため、統一されたフォーマットが求められていました。
この問題はIssue #8175として報告され、このコミットはその解決のために行われました。Go Code Review (CL 103320043)での議論を経て、"%.2fs"という形式で秒単位の時間を小数点以下2桁まで表示する形式に統一することが決定されました。
前提知識の解説
go testコマンド: Go言語のテストを実行するためのコマンドです。プロジェクトのルートディレクトリでgo testを実行すると、テストファイル(ファイル名が_test.goで終わるファイル)内のテスト関数(関数名がTestで始まる関数)やExample関数(関数名がExampleで始まる関数)が実行されます。testingパッケージ: Go言語に組み込まれているテストフレームワークを提供するパッケージです。testing.T型はテスト関数に、testing.B型はベンチマーク関数に、そしてtesting.Example型はExample関数に渡され、テストの実行、結果の報告、ヘルパー関数の提供などを行います。time.Duration型:timeパッケージで定義されている型で、時間の長さを表します。内部的にはナノ秒単位の整数で表現されます。time.Duration型の値は、String()メソッドを呼び出すことで人間が読みやすい形式(例:1h2m3s)に変換できますが、このコミットでは特定の数値形式での出力が求められました。fmt.Sprintf関数:fmtパッケージで提供される関数で、指定されたフォーマット文字列に従って値を整形し、文字列として返します。C言語のsprintfに似ています。このコミットでは、"%.2fs"というフォーマット文字列を使用して、time.Durationの秒数を小数点以下2桁まで表示する形式に整形しています。
技術的詳細
このコミットの技術的な核心は、テストおよびExampleの実行時間表示を統一するために、testingパッケージ内に新しいヘルパー関数fmtDurationを導入し、既存のコードで時間の表示を行っていた箇所をこの関数を使用するように変更した点です。
以前は、time.Duration型の値を直接fmt.Printfに渡したり、duration.Seconds()の結果を直接フォーマットしたりしていました。これにより、出力形式にばらつきが生じていました。
新しいfmtDuration関数は以下のようになっています。
// fmtDuration returns a string representing d in the form "87.00s".
func fmtDuration(d time.Duration) string {
return fmt.Sprintf("%.2fs", d.Seconds())
}
この関数は、time.Duration型の引数dを受け取り、そのSeconds()メソッドを呼び出して秒単位の浮動小数点数に変換します。その後、fmt.Sprintf("%.2fs", ...)を使用して、この秒数を小数点以下2桁の浮動小数点数として整形し、末尾にs(秒)を付けた文字列を返します。例えば、87.12345sのようなDurationは"87.12s"と表示されます。
このfmtDuration関数が導入されたことで、src/pkg/testing/example.goとsrc/pkg/testing/testing.go内の、テストやExampleの実行時間を表示するすべての箇所で、この統一されたフォーマットが適用されるようになりました。これにより、出力の不整合が解消され、機械的な解析が容易になりました。
コアとなるコードの変更箇所
このコミットによって変更された主要なファイルとコード箇所は以下の通りです。
-
src/pkg/testing/example.go: Exampleの実行結果を報告するrunExample関数内で、実行時間の表示形式が変更されました。- 変更前:
fmt.Printf("--- FAIL: %s (%v)\\n%s", eg.Name, d, fail)のように、time.Duration型のdを直接%vで表示していた。 - 変更後:
dstr := fmtDuration(time.Now().Sub(start))でfmtDurationを呼び出し、fmt.Printf("--- FAIL: %s (%s)\\n%s", eg.Name, dstr, fail)のように、dstr(整形済みの文字列)を使用するように変更。
- 変更前:
-
src/pkg/testing/testing.go:- 新しいヘルパー関数
fmtDurationが追加されました。 testing.T型のreportメソッド内で、テスト結果を報告する際の実行時間の表示形式が変更されました。- 変更前:
tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())のように、秒数を"%.2f seconds"で表示していた。 - 変更後:
dstr := fmtDuration(t.duration)でfmtDurationを呼び出し、format := "--- %s: %s (%s)\\n%s"とフォーマット文字列も変更し、fmt.Printf(format, "FAIL", t.name, dstr, t.output)のように、dstr(整形済みの文字列)を使用するように変更。
- 変更前:
- 新しいヘルパー関数
コアとなるコードの解説
src/pkg/testing/testing.goにおけるfmtDuration関数の追加
// fmtDuration returns a string representing d in the form "87.00s".
func fmtDuration(d time.Duration) string {
return fmt.Sprintf("%.2fs", d.Seconds())
}
この関数は、time.Duration型の値を秒単位の浮動小数点数に変換し、それを小数点以下2桁まで表示する"%.2fs"という形式の文字列に整形します。これにより、テストやExampleの実行時間が常に統一された形式で出力されるようになります。
src/pkg/testing/example.goにおける変更
runExample関数は、Exampleの実行を管理し、その結果を標準出力に報告します。以前は、実行時間をtime.Duration型のデフォルトの文字列表現(%vフォーマット)で出力していましたが、これは秒単位の精度が一定ではありませんでした。
// 変更前
// d := time.Now().Sub(start)
// fmt.Printf("--- FAIL: %s (%v)\\n%s", eg.Name, d, fail)
// 変更後
dstr := fmtDuration(time.Now().Sub(start)) // 新しいfmtDuration関数を使用
fmt.Printf("--- FAIL: %s (%s)\\n%s", eg.Name, dstr, fail)
この変更により、Exampleの実行時間も"87.00s"のような統一された形式で表示されるようになりました。
src/pkg/testing/testing.goにおけるreportメソッドの変更
reportメソッドは、個々のテスト(*testing.T)の最終結果(PASS/FAIL/SKIP)を報告する際に呼び出されます。以前は、t.duration.Seconds()を直接fmt.Sprintfでフォーマットしていましたが、このコミットではfmtDuration関数を使用するように変更されました。
// 変更前
// tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
// format := "--- %s: %s %s\\n%s"
// fmt.Printf(format, "FAIL", t.name, tstr, t.output)
// 変更後
dstr := fmtDuration(t.duration) // 新しいfmtDuration関数を使用
format := "--- %s: %s (%s)\\n%s" // フォーマット文字列も変更
fmt.Printf(format, "FAIL", t.name, dstr, t.output)
この変更により、テストの実行時間もExampleと同様に"87.00s"のような統一された形式で表示されるようになり、testingパッケージ全体での時間表示の一貫性が確保されました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/0e92b538a9f6e337b8e48f47f38803e8245c03cc
- Go Code Review (CL 103320043): https://golang.org/cl/103320043
参考にした情報源リンク
- Go Code Review (CL 103320043) の内容
- Go言語の
testingパッケージに関する一般的なドキュメント - Go言語の
timeパッケージに関する一般的なドキュメント - Go言語の
fmtパッケージに関する一般的なドキュメント - Web検索: "Go testing package timing format inconsistency"
- Web検索: "Go issue 8175" (直接的な結果は得られなかったが、CLの情報を補完するために使用)