[インデックス 18151] ファイルの概要
このコミットは、Go言語の標準ライブラリtime
パッケージにおけるDuration
型のNanoseconds()
, Minutes()
, Hours()
メソッドに対するテストを追加するものです。これらのメソッドは、Duration
型の値をそれぞれナノ秒、分、時間の単位で表現した数値として返します。
コミット
commit b38da05ab15e9414ffcbf7f5ea3cf390e16e719c
Author: Shawn Smith <shawn.p.smith@gmail.com>
Date: Thu Jan 2 21:01:18 2014 +1100
time: add tests for Duration.Nanoseconds, Duration.Minutes, and Duration.Hours
R=golang-codereviews, rsc, dave
CC=golang-codereviews
https://golang.org/cl/42440043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b38da05ab15e9414ffcbf7f5ea3cf390e16e719c
元コミット内容
time: add tests for Duration.Nanoseconds, Duration.Minutes, and Duration.Hours
このコミットは、time
パッケージのDuration
型に存在するNanoseconds()
, Minutes()
, Hours()
メソッドに対して、新たなテストケースを追加することを目的としています。これにより、これらのメソッドが様々なDuration
値に対して正しく動作することを保証します。
変更の背景
Go言語の標準ライブラリは、その堅牢性と信頼性を維持するために、厳格なテストカバレッジを重視しています。time.Duration
型は、時間間隔を表現するための基本的な型であり、その変換メソッド(Nanoseconds
, Minutes
, Hours
)は多くのアプリケーションで利用されます。これらのメソッドが予期せぬ挙動をしないことを保証するためには、包括的なテストが不可欠です。
このコミットが行われた2014年当時、Go言語はまだ比較的新しい言語であり、標準ライブラリの成熟度を高めるための継続的な改善が行われていました。既存の機能に対するテストの拡充は、ライブラリの安定性を向上させ、将来の変更に対する回帰を防ぐ上で重要なステップでした。特に、浮動小数点数を含む時間単位への変換は、精度に関する潜在的な問題を引き起こす可能性があるため、様々なエッジケース(負の値、非常に小さい値、非常に大きい値)に対するテストが求められていました。
前提知識の解説
Go言語のtime
パッケージ
Go言語のtime
パッケージは、時間の測定、表示、および操作のための機能を提供します。日付と時刻、期間(Duration)、タイマー、ティックなどの概念を扱います。
time.Duration
型
time.Duration
は、Go言語で時間間隔を表すために使用される型です。これはint64
のエイリアスであり、ナノ秒単位で時間間隔を格納します。例えば、time.Second
は1秒を表すDuration
定数であり、これは10億ナノ秒(1e9
)に相当します。
Duration
型は、以下のようなメソッドを提供します。
Nanoseconds() int64
:Duration
をナノ秒単位のint64
として返します。Microseconds() int64
:Duration
をマイクロ秒単位のint64
として返します。Milliseconds() int64
:Duration
をミリ秒単位のint64
として返します。Seconds() float64
:Duration
を秒単位のfloat64
として返します。Minutes() float64
:Duration
を分単位のfloat64
として返します。Hours() float64
:Duration
を時間単位のfloat64
として返します。
これらのメソッドは、異なる時間単位での表現が必要な場合に非常に便利です。特にMinutes()
やHours()
のように浮動小数点数を返すメソッドは、計算の精度が重要になります。
Go言語のテストフレームワーク
Go言語には、標準でtesting
パッケージが提供されており、ユニットテストやベンチマークテストを簡単に記述できます。テストファイルは通常、テスト対象のソースファイルと同じディレクトリに配置され、ファイル名の末尾に_test.go
が付きます。テスト関数はTest
で始まり、*testing.T
型の引数を取ります。
テストケースは、構造体のスライスとして定義されることが多く、各要素が入力と期待される出力を含みます。これにより、複数のテストシナリオを簡潔に記述し、ループで実行することができます。
技術的詳細
このコミットでは、src/pkg/time/time_test.go
ファイルに以下の3つの新しいテスト関数が追加されています。
TestDurationNanoseconds
:Duration.Nanoseconds()
メソッドのテスト。TestDurationMinutes
:Duration.Minutes()
メソッドのテスト。TestDurationHours
:Duration.Hours()
メソッドのテスト。
それぞれのテスト関数は、対応するメソッドの動作を検証するために、異なるDuration
値とそれに対応する期待される結果(ナノ秒、分、時間)のペアを含むテストデータスライスを使用しています。
TestDurationNanoseconds
nsDurationTests
というstruct
のスライスが定義されており、Duration
値と期待されるint64
のナノ秒値が含まれています。テストケースには、負の値、非常に小さい値、正の値、比較的大きい値が含まれており、Nanoseconds()
メソッドがDuration
の内部表現(ナノ秒)をそのままint64
として返すことを確認します。
TestDurationMinutes
minDurationTests
というstruct
のスライスが定義されており、Duration
値と期待されるfloat64
の分値が含まれています。ここでの重要な点は、Duration
がナノ秒単位で格納されているため、分に変換するには60 * 1e9
(1分あたりのナノ秒数)で割る必要があることです。テストケースには、負の値、非常に小さい値(1ナノ秒)、正の値、1分に相当する値が含まれており、浮動小数点数演算の精度も考慮されています。
TestDurationHours
hourDurationTests
というstruct
のスライスが定義されており、Duration
値と期待されるfloat64
の時間値が含まれています。同様に、時間に変換するには3600 * 1e9
(1時間あたりのナノ秒数)で割る必要があります。テストケースはMinutes
のテストと同様に、様々な値で変換の正確性を検証しています。
これらのテストは、Duration
型の内部表現がナノ秒であることを前提とし、各メソッドがそのナノ秒値を指定された単位に正しく変換しているかを検証しています。特にMinutes()
とHours()
では浮動小数点数での比較が行われるため、厳密な等価性ではなく、ある程度の許容誤差を考慮した比較が理想的ですが、このコミットでは厳密な等価性で比較されています。これは、Goのtime
パッケージの設計上、これらの変換が正確な浮動小数点数で表現可能であるという前提に基づいている可能性があります。
コアとなるコードの変更箇所
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -1461,6 +1461,60 @@ func TestSub(t *testing.T) {
}\n
}\n
\n+var nsDurationTests = []struct {\n+ d Duration\n+ want int64\n+}{\n+ {Duration(-1000), -1000},\n+ {Duration(-1), -1},\n+ {Duration(1), 1},\n+ {Duration(1000), 1000},\n+}\n+\n+func TestDurationNanoseconds(t *testing.T) {\n+ for _, tt := range nsDurationTests {\n+ if got := tt.d.Nanoseconds(); got != tt.want {\n+ t.Errorf("d.Nanoseconds() = %d; want: %d", got, tt.want)\n+ }\n+ }\n+}\n+\n+var minDurationTests = []struct {\n+ d Duration\n+ want float64\n+}{\n+ {Duration(-60000000000), -1},\n+ {Duration(-1), -1 / 60e9},\n+ {Duration(1), 1 / 60e9},\n+ {Duration(60000000000), 1},\n+}\n+\n+func TestDurationMinutes(t *testing.T) {\n+ for _, tt := range minDurationTests {\n+ if got := tt.d.Minutes(); got != tt.want {\n+ t.Errorf("d.Minutes() = %d; want: %d", got, tt.want)\n+ }\n+ }\n+}\n+\n+var hourDurationTests = []struct {\n+ d Duration\n+ want float64\n+}{\n+ {Duration(-3600000000000), -1},\n+ {Duration(-1), -1 / 3600e9},\n+ {Duration(1), 1 / 3600e9},\n+ {Duration(3600000000000), 1},\n+}\n+\n+func TestDurationHours(t *testing.T) {\n+ for _, tt := range hourDurationTests {\n+ if got := tt.d.Hours(); got != tt.want {\n+ t.Errorf("d.Hours() = %d; want: %d", got, tt.want)\n+ }\n+ }\n+}\n+\n func BenchmarkNow(b *testing.B) {\n for i := 0; i < b.N; i++ {\n t = Now()\n```
## コアとなるコードの解説
追加されたコードは、Goの`testing`パッケージの慣例に従って、テーブル駆動テスト(table-driven tests)の形式で記述されています。
### `nsDurationTests`と`TestDurationNanoseconds`
`nsDurationTests`は、`Duration`型の入力`d`と、それに対応する期待されるナノ秒値`want`を持つ匿名構造体のスライスです。
`TestDurationNanoseconds`関数は、このスライスをループで処理し、各テストケースに対して以下のことを行います。
1. `tt.d.Nanoseconds()`を呼び出して実際の結果`got`を取得します。
2. `got`と`tt.want`を比較します。
3. もし一致しない場合、`t.Errorf`を呼び出してエラーメッセージを出力し、テストを失敗させます。
### `minDurationTests`と`TestDurationMinutes`
`minDurationTests`は、`Duration`型の入力`d`と、それに対応する期待される分値`want`(`float64`)を持つ匿名構造体のスライスです。
`TestDurationMinutes`関数は、`nsDurationTests`と同様にループ処理を行い、`tt.d.Minutes()`の結果を`tt.want`と比較します。注目すべきは、`Duration(-1)`のような非常に小さい値が、`1 / 60e9`という浮動小数点数で表現されることです。これは、1ナノ秒が1分の`1/(60 * 10^9)`であることを示しています。
### `hourDurationTests`と`TestDurationHours`
`hourDurationTests`は、`Duration`型の入力`d`と、それに対応する期待される時間値`want`(`float64`)を持つ匿名構造体のスライスです。
`TestDurationHours`関数も同様にループ処理を行い、`tt.d.Hours()`の結果を`tt.want`と比較します。ここでも、`Duration(-1)`が`1 / 3600e9`という浮動小数点数で表現されており、1ナノ秒が1時間の`1/(3600 * 10^9)`であることを示しています。
これらのテストは、`Duration`型の変換メソッドが、正の値、負の値、そして非常に小さい値(1ナノ秒)に対しても正確な結果を返すことを検証しています。これにより、`time`パッケージの堅牢性が向上し、開発者がこれらのメソッドを安心して利用できるようになります。
## 関連リンク
* Go言語 `time`パッケージのドキュメント: [https://pkg.go.dev/time](https://pkg.go.dev/time)
* Go言語のテストに関するドキュメント: [https://go.dev/blog/testing](https://go.dev/blog/testing)
## 参考にした情報源リンク
* Go言語の公式ドキュメント
* Go言語のソースコード(`src/pkg/time/time.go` および `src/pkg/time/time_test.go`)
* GitHubのコミットページ: [https://github.com/golang/go/commit/b38da05ab15e9414ffcbf7f5ea3cf390e16e719c](https://github.com/golang/go/commit/b38da05ab15e9414ffcbf7f5ea3cf390e16e719c)
* Gerrit Code Review: [https://golang.org/cl/42440043](https://golang.org/cl/42440043) (コミットメッセージに記載されているCLリンク)