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

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

このコミットは、Go言語の標準ライブラリにおけるcrypto/des, crypto/md5, crypto/sha1パッケージのテストコードの構成に関する変更です。具体的には、各パッケージ内に直接記述されていたExample関数を、_testサフィックスを持つ独立したファイル(例: example_test.go)に移動しています。これにより、テストコードとExampleコードの役割分担が明確化され、GoのテストフレームワークにおけるExampleの意図がより適切に反映されるようになります。

コミット

commit b7c3d06a1fbad0df04773e8b6825689ae6bde41b
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Mon Jul 29 01:25:51 2013 +0200

    all: move examples into package *_test.
    
    Fixes #5677.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/11992043

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

https://github.com/golang/go/commit/b7c3d06a1fbad0df04773e8b6825689ae6bde41b

元コミット内容

all: move examples into package *_test.

Fixes #5677.

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

変更の背景

この変更の背景には、Go言語のテストおよびドキュメンテーションシステムにおけるExample関数の役割と、その配置に関するベストプラクティスの確立があります。

Go言語では、go testコマンドは単体テストだけでなく、Example関数も実行し、その出力を検証します。Example関数は、パッケージの利用方法を示すコード例として機能し、go docコマンドによって生成されるドキュメンテーションにも自動的に組み込まれます。これにより、開発者はコードの動作例を簡単に確認でき、ドキュメントの鮮度も保たれます。

しかし、Example関数が通常のテストファイル(例: _test.go)内に混在していると、以下のような問題が生じる可能性がありました。

  1. 役割の曖昧さ: テスト関数とExample関数は、どちらも_test.goファイルに記述されますが、その目的は異なります。テスト関数はコードの正確性を検証するものであり、Example関数はコードの利用方法を示すものです。これらが混在していると、ファイルの意図が不明瞭になることがあります。
  2. パッケージ名の問題: Example関数は、通常、テスト対象のパッケージと同じパッケージ名(例: package des)で記述されます。しかし、Goのテスト慣習では、テストファイルはpackage des_testのように、テスト対象のパッケージとは異なるパッケージ名で記述されることが推奨されます。これにより、テストコードがテスト対象のパッケージの内部実装に依存しすぎず、公開APIのみをテストする「ブラックボックステスト」の原則が守られます。Example関数が_testパッケージに移動されることで、Example関数もこの慣習に従うことができ、よりクリーンな分離が実現されます。
  3. ドキュメンテーションの整合性: go docは、_testサフィックスのないパッケージファイルからExample関数を抽出します。Example関数が_test.goファイル内に存在する場合、そのExampleがドキュメンテーションに適切に表示されない、あるいは意図しない形で表示される可能性がありました。独立したexample_test.goファイルに移動することで、Exampleがドキュメンテーションシステムによって正しく認識され、表示されるようになります。

このコミットは、Go Issue #5677「go doc should show examples from _test.go files」に対応するものであり、Example関数を専用の_testパッケージファイルに移動することで、これらの問題を解決し、Goのテストおよびドキュメンテーションエコシステムをより堅牢で使いやすいものにすることを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と慣習に関する知識が必要です。

  1. Goのパッケージシステム:

    • Goのコードは「パッケージ」という単位で整理されます。パッケージは、関連する機能を持つGoソースファイルの集合です。
    • 同じディレクトリ内のGoファイルは、通常、同じパッケージに属します。
    • パッケージは、他のパッケージからインポートして利用できます。
    • パッケージ名とディレクトリ名は、通常一致します。
  2. Goのテストフレームワーク (testingパッケージ):

    • Goには、標準ライブラリとしてtestingパッケージが提供されており、これを用いて単体テスト、ベンチマークテスト、Exampleテストを記述できます。
    • テストファイルは、慣習的に_test.goというサフィックスを持ちます。
    • go testコマンドを実行すると、これらのテストファイルがコンパイルされ、実行されます。
  3. テストパッケージの慣習 (package _test):

    • Goのテストファイルは、テスト対象のパッケージと同じパッケージ名(例: package mypackage)で記述することもできますし、package mypackage_testのように、_testサフィックスを付けた異なるパッケージ名で記述することもできます。
    • package mypackage_testを使用する利点は、テストコードがテスト対象パッケージの公開APIのみにアクセスできるため、テストがより「ブラックボックス的」になり、外部から見た場合のパッケージの振る舞いを検証するのに適している点です。これにより、テストがパッケージの内部実装の変更に影響されにくくなります。
    • このコミットでは、Example関数を_testサフィックスを持つパッケージに移動しているため、この慣習がExampleにも適用されることになります。
  4. Example関数:

    • Example関数は、func ExampleFunctionName()func ExampleType_MethodName()func Example()といった命名規則に従う関数です。
    • これらの関数は、go testコマンドによって実行され、その標準出力がコメントで指定されたOutput:行と一致するかどうかが検証されます。
    • Example関数は、go docコマンドによって生成されるドキュメンテーションに自動的に組み込まれ、パッケージの利用例として表示されます。これは、コードとドキュメントの同期を保つ上で非常に強力な機能です。
    • Example関数は、テスト対象のパッケージと同じパッケージ名で記述されることが一般的ですが、このコミットのように_testパッケージに移動することも可能です。_testパッケージに移動した場合、Example関数はテスト対象パッケージの公開APIのみを使用することになります。
  5. go docコマンド:

    • go doc <package_path>コマンドは、指定されたパッケージのドキュメンテーションを生成し、表示します。
    • このドキュメンテーションには、パッケージのコメント、公開された型、関数、メソッドのシグネチャとコメント、そしてExample関数が含まれます。

これらの概念を理解することで、このコミットがGoのテストとドキュメンテーションのベストプラクティスをどのように強化しているかが明確になります。

技術的詳細

このコミットの技術的な詳細は、GoのビルドシステムとテストフレームワークがExample関数をどのように扱うか、そして_testパッケージの慣習がどのように適用されるかに集約されます。

変更前は、Example関数が通常のテストファイル(例: des_test.go)内に記述されていました。これらのファイルは、テスト対象のパッケージと同じパッケージ名(例: package des)で記述されていることが多かったです。この場合、Example関数はテスト対象パッケージの内部要素にもアクセスできてしまいます。

変更後、Example関数はexample_test.goという新しいファイルに移動され、これらのファイルはpackage des_testのように、_testサフィックスを持つパッケージ名で記述されています。

この変更がもたらす技術的な影響は以下の通りです。

  1. パッケージの分離:

    • des_test.goのような通常のテストファイルは、引き続きpackage des(またはpackage des_test)として存在し、単体テストを実行します。
    • 新しく作成されたexample_test.goファイルは、package des_testとして定義されます。これにより、Example関数はテスト対象のパッケージ(des)の公開されたAPIのみをインポートして使用するようになります。これは、Exampleがユーザーが実際にパッケージを使用する際のシナリオを正確に反映するために重要です。内部実装に依存するExampleは、APIの変更によって壊れやすくなるため、この分離は堅牢性を高めます。
  2. go testの振る舞い:

    • go testコマンドは、_test.goファイル内のすべてのテスト関数(TestXxx)、ベンチマーク関数(BenchmarkXxx)、およびExample関数(ExampleXxx)を自動的に発見し、実行します。
    • _testパッケージにExample関数が移動されても、go testは引き続きそれらを検出し、実行し、Output:コメントとの一致を検証します。この機能的な振る舞いは変わりません。
  3. go docの振る舞い:

    • go docコマンドは、パッケージのドキュメンテーションを生成する際に、_testサフィックスのないファイル(例: des.go)だけでなく、_testサフィックスを持つファイル(例: des_test.goexample_test.go)からもExample関数を抽出して表示するようになりました。
    • このコミットは、Go Issue #5677で提起された問題、すなわち_test.goファイル内のExampleがgo docで表示されないという問題を解決しています。Example関数を専用のexample_test.goファイルに移動し、それを_testパッケージとして定義することで、go docがこれらのExampleを正しく認識し、ドキュメンテーションに含めることができるようになります。
  4. 依存関係の管理:

    • example_test.goファイルは、テスト対象のパッケージ(例: crypto/des)を明示的にインポートする必要があります。例えば、import "crypto/des"のように記述されます。これにより、Exampleコードがどのパッケージの機能を使用しているかが明確になります。
    • 元のdes_test.goファイルでは、Example関数が同じパッケージ内にあったため、明示的なインポートは不要でした。この変更により、Exampleの依存関係がより透過的になります。

この変更は、Goの標準ライブラリ全体にわたるExampleの管理とドキュメンテーションの品質を向上させるための、体系的なリファクタリングの一環と言えます。

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

このコミットでは、以下のファイルが変更されています。

  1. src/pkg/crypto/des/des_test.go:

    • ExampleNewTripleDESCipher関数が削除されました。
  2. src/pkg/crypto/des/example_test.go:

    • 新規作成されたファイル。
    • package des_testとして定義されています。
    • import "crypto/des"が追加されています。
    • ExampleNewTripleDESCipher関数がここに移されました。
  3. src/pkg/crypto/md5/example_test.go:

    • 新規作成されたファイル。
    • package md5_testとして定義されています。
    • import ("crypto/md5"; "fmt"; "io")が追加されています。
    • ExampleNew関数がここに移されました。
  4. src/pkg/crypto/md5/md5_test.go:

    • ExampleNew関数が削除されました。
  5. src/pkg/crypto/sha1/example_test.go:

    • 新規作成されたファイル。
    • package sha1_testとして定義されています。
    • import ("crypto/sha1"; "fmt"; "io")が追加されています。
    • ExampleNew関数がここに移されました。
  6. src/pkg/crypto/sha1/sha1_test.go:

    • ExampleNew関数が削除されました。

具体的な差分 (diff):

--- a/src/pkg/crypto/des/des_test.go
+++ b/src/pkg/crypto/des/des_test.go
@@ -1504,24 +1504,6 @@ func TestSubstitutionTableKnownAnswerDecrypt(t *testing.T) {
 	}
 }
 
--func ExampleNewTripleDESCipher() {
--	// NewTripleDESCipher can also be used when EDE2 is required by
--	// duplicating the first 8 bytes of the 16-byte key.
--	ede2Key := []byte("example key 1234")
--
--	var tripleDESKey []byte
--	tripleDESKey = append(tripleDESKey, ede2Key[:16]...)
--	tripleDESKey = append(tripleDESKey, ede2Key[:8]...)
--
--	_, err := NewTripleDESCipher(tripleDESKey)
--	if err != nil {
--		panic(err)
--	}
--
--	// See crypto/cipher for how to use a cipher.Block for encryption and
--	// decryption.
-}
-
 func BenchmarkEncrypt(b *testing.B) {
 	tt := encryptDESTests[0]
 	c, err := NewCipher(tt.key)
diff --git a/src/pkg/crypto/des/example_test.go b/src/pkg/crypto/des/example_test.go
new file mode 100644
index 0000000000..336b593756
--- /dev/null
+++ b/src/pkg/crypto/des/example_test.go
@@ -0,0 +1,25 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des_test
+
+import "crypto/des"
+
+func ExampleNewTripleDESCipher() {
+	// NewTripleDESCipher can also be used when EDE2 is required by
+	// duplicating the first 8 bytes of the 16-byte key.
+	ede2Key := []byte("example key 1234")
+
+	var tripleDESKey []byte
+	tripleDESKey = append(tripleDESKey, ede2Key[:16]...)
+	tripleDESKey = append(tripleDESKey, ede2Key[:8]...)
+
+	_, err := des.NewTripleDESCipher(tripleDESKey)
+	if err != nil {
+		panic(err)
+	}
+
+	// See crypto/cipher for how to use a cipher.Block for encryption and
+	// decryption.
+}

(他のファイルも同様のパターンで変更されています。)

コアとなるコードの解説

このコミットのコアとなる変更は、Example関数の物理的な配置と、それに伴うパッケージ名の変更です。

例えば、crypto/desパッケージの場合、変更前はsrc/pkg/crypto/des/des_test.go内にExampleNewTripleDESCipher関数がありました。このファイルはpackage desとして定義されていた可能性があります(コミットログからは直接確認できませんが、一般的な慣習です)。

変更後、ExampleNewTripleDESCipher関数はsrc/pkg/crypto/des/example_test.goという新しいファイルに移動されました。この新しいファイルの冒頭には、以下の行が追加されています。

package des_test

import "crypto/des"

これは、以下の重要な点を意味します。

  1. package des_test: このExample関数が、テスト対象のdesパッケージとは異なる、独立したdes_testパッケージに属していることを示します。これにより、Exampleコードはdesパッケージの公開されたAPIのみにアクセスできるようになります。例えば、des.NewTripleDESCipherのように、パッケージ名をプレフィックスとして関数を呼び出す必要があります。もしExampleが元のdesパッケージ内にあった場合、NewTripleDESCipherと直接呼び出すことができました。この変更は、Exampleがユーザーがパッケージをインポートして使用する際の実際のシナリオをより正確に反映するようにします。

  2. import "crypto/des": des_testパッケージは、desパッケージの機能を利用するために、明示的にcrypto/desをインポートしています。これは、異なるパッケージ間でコードを共有する際のGoの標準的な方法です。

同様の変更がcrypto/md5crypto/sha1パッケージにも適用されています。

  • crypto/md5/md5_test.goからExampleNew関数が削除され、crypto/md5/example_test.goに移動し、package md5_testとして定義されました。
  • crypto/sha1/sha1_test.goからExampleNew関数が削除され、crypto/sha1/example_test.goに移動し、package sha1_testとして定義されました。

この一連の変更は、Goのテストとドキュメンテーションのベストプラクティスに沿って、Exampleコードをより構造化し、その役割を明確にするためのものです。これにより、Exampleはより独立した形で機能し、go docによって適切にドキュメンテーションに組み込まれるようになります。

関連リンク

参考にした情報源リンク