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

[インデックス 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つの新しいテスト関数が追加されています。

  1. TestDurationNanoseconds: Duration.Nanoseconds()メソッドのテスト。
  2. TestDurationMinutes: Duration.Minutes()メソッドのテスト。
  3. 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リンク)