[インデックス 11999] ファイルの概要
このコミットは、Go言語のテストスイートにおけるテストファイルの記述方法を標準化し、簡素化することを目的としています。具体的には、各テストファイルの先頭に記述されていた複雑なシェルコマンドベースのテスト実行指示を、testlib
という内部的なテストユーティリティが解釈する、より簡潔なキーワード(compile
, run
, errorcheck
など)に置き換える変更が行われています。これにより、テストコードの可読性と保守性が向上し、テストインフラストラクチャの統一が図られています。
コミット
- コミットハッシュ:
8080384a68850b47d7c5a85f7f904de80a3ae449
- Author: Russ Cox rsc@golang.org
- Date: Thu Feb 16 23:49:59 2012 -0500
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8080384a68850b47d7c5a85f7f904de80a3ae449
元コミット内容
test: use testlib (third 100)
X ,s;^// \$G (\$D/)?\$F\.go *$;// compile;g
X ,s;^// \$G (\$D/)?\$F\.go && \$L \$F\.\$A *$;// build;g
X ,s;^// \$G (\$D/)?\$F\.go && \$L \$F\.\$A && \./\$A\.out *$;// run;g
X ,s;^// errchk \$G( -e)? (\$D/)?\$F\.go *$;// errorcheck;g
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5656083
変更の背景
Go言語の初期のテストフレームワークでは、各テストファイルの先頭にコメント形式でシェルコマンドを直接記述することで、そのテストの実行方法(コンパイルのみ、実行、エラーチェックなど)を指示していました。これは柔軟性を提供する一方で、コマンドが複雑になりがちで、可読性の低下やメンテナンスの困難さを招いていました。
このコミットは、Goプロジェクト内で開発されたtestlib
という内部ユーティリティの導入の一環として行われました。testlib
は、これらの複雑なシェルコマンドを抽象化し、よりシンプルで人間が理解しやすいキーワードにマッピングすることで、テストの記述と管理を容易にすることを目的としています。この変更は、テストインフラストラクチャの統一と、将来的な拡張性・保守性の向上に寄与します。
前提知識の解説
Go言語のテストの基本
Go言語には、標準ライブラリとしてtesting
パッケージが組み込まれており、これを用いてユニットテスト、ベンチマークテスト、サンプルコードのテストなどを記述します。go test
コマンドは、このtesting
パッケージを利用してテストを実行するための主要なツールです。
Goテストファイルにおける「マジックコメント」またはテストディレクティブ
Goのテストシステムでは、テストファイルの先頭に特定の形式のコメントを記述することで、go test
コマンドや関連ツールに対して特別な指示を与えることができます。これらは「マジックコメント」や「テストディレクティブ」と呼ばれることがあります。このコミット以前は、これらのディレクティブはシェルコマンドの形式で記述されていました。
// $G ...
: Goコンパイラ(go tool compile
)を実行するコマンドを示します。// $L ...
: Goリンカ(go tool link
)を実行するコマンドを示します。// errchk ...
: コンパイル時のエラーチェックを行うテストであることを示します。$D
: テストファイルが存在するディレクトリのパスを表す変数です。$F
: テストファイルの名前(拡張子含む)を表す変数です。$A
: 生成される実行可能ファイルの名前を表す変数です。
例えば、// $G $D/$F.go && $L $F.$A && ./$A.out
は、「テストファイルをコンパイルし、リンクして実行可能ファイルを生成し、その実行可能ファイルを実行する」という一連の操作を意味していました。
testlib
の概念
testlib
は、Goプロジェクトの内部で利用されるテストヘルパーライブラリであり、Goのテストフレームワークの機能を拡張し、より高度なテストシナリオを簡潔に記述できるようにするためのものです。このコミットでは、testlib
がテストファイルの先頭に記述された簡潔なキーワードを解釈し、対応する内部的なテストロジックを実行するようになりました。これにより、テストファイルの記述者は、複雑なシェルコマンドの詳細を知る必要がなくなり、テストの意図をより明確に表現できるようになります。
技術的詳細
このコミットの技術的な核心は、Goのテストシステムがテストファイルの先頭のコメントを解釈する方法の変更にあります。以前は、正規表現とシェルコマンドの組み合わせでテストの挙動を定義していましたが、この変更により、より高レベルな抽象化が導入されました。
変更前は、例えばテストのコンパイルと実行を行うには以下のような行が必要でした。
// $G $D/$F.go && $L $F.$A && ./$A.out
これは、Goコンパイラ($G
)を使って$D/$F.go
(テストファイル)をコンパイルし、成功したら(&&
)Goリンカ($L
)を使って$F.$A
(生成されるオブジェクトファイル)をリンクし、さらに成功したら(&&
)生成された実行可能ファイル(./$A.out
)を実行するという、複数のステップからなるシェルコマンドでした。
このコミットでは、これらの複雑なコマンドが、testlib
によって解釈される単一のキーワードに置き換えられました。
// compile
:テストファイルをコンパイルするだけ。// build
:テストファイルをコンパイルし、実行可能ファイルをビルドするだけ(実行はしない)。// run
:テストファイルをコンパイル、ビルドし、実行可能ファイルを実行する。// errorcheck
:テストファイルをコンパイルし、期待されるエラーが出力されるかチェックする。
この変更により、テストファイルの先頭のコメントは、そのテストが何を行うのかを直感的に示すものとなり、テストの意図がより明確になりました。testlib
が内部でこれらのキーワードを適切なコンパイル、リンク、実行、エラーチェックのコマンドに変換するため、テストファイルの記述者は低レベルなコマンドの詳細を意識する必要がなくなります。これは、テストコードの可読性、保守性、そしてテストインフラストラクチャ全体の堅牢性を大幅に向上させます。
コアとなるコードの変更箇所
このコミットでは、test/fixedbugs
ディレクトリ内の多数のGoテストファイル(99ファイル)が変更されています。各ファイルの変更は非常にシンプルで、ファイルの先頭にあるテストディレクティブのコメント行が、古いシェルコマンド形式から新しいキーワード形式に置き換えられています。
例: test/fixedbugs/bug235.go
--- a/test/fixedbugs/bug235.go
+++ b/test/fixedbugs/bug235.go
@@ -1,4 +1,4 @@
-// $G $D/$F.go
+// compile
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
例: test/fixedbugs/bug236.go
--- a/test/fixedbugs/bug236.go
+++ b/test/fixedbugs/bug236.go
@@ -1,4 +1,4 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
+// run
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
例: test/fixedbugs/bug238.go
--- a/test/fixedbugs/bug238.go
+++ b/test/fixedbugs/bug238.go
@@ -1,4 +1,4 @@
-// errchk $G -e $D/$F.go
+// errorcheck
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
これらの変更は、各テストファイルの先頭の1行のみに集中しており、古い複雑な正規表現ベースのシェルコマンドが、対応する簡潔なキーワードに置き換えられています。
コアとなるコードの解説
変更された各テストファイルでは、以下のマッピングに基づいてテストディレクティブが更新されています。
-
// $G ($D/)?$F\.go
- これは、Goコンパイラ(
$G
)を使用して指定されたGoファイルをコンパイルするだけのテストを示していました。 - 新しい形式では、
// compile
に置き換えられました。これは、テストファイルが単にコンパイル可能であることを確認するテストであることを意味します。
- これは、Goコンパイラ(
-
// $G ($D/)?$F\.go && $L $F\.$A
- これは、Goファイルをコンパイルし、さらにリンクして実行可能ファイルをビルドするテストを示していました。ただし、実行はしません。
- 新しい形式では、
// build
に置き換えられました。これは、テストファイルが正常にビルドできることを確認するテストであることを意味します。
-
// $G ($D/)?$F\.go && $L $F\.$A && \./$A\.out
- これは、Goファイルをコンパイル、リンクし、生成された実行可能ファイルを実行するテストを示していました。
- 新しい形式では、
// run
に置き換えられました。これは、テストファイルが正常に実行され、期待される出力や挙動を示すことを確認するテストであることを意味します。
-
// errchk $G( -e)? ($D/)?$F\.go
- これは、Goファイルをコンパイルした際に、特定のコンパイルエラーが発生することを期待するテストを示していました。
-e
オプションは、エラーメッセージの正規表現マッチングを意味することがあります。 - 新しい形式では、
// errorcheck
に置き換えられました。これは、テストファイルがコンパイルエラーを引き起こすことを意図しており、そのエラーが期待通りであることを確認するテストであることを意味します。
- これは、Goファイルをコンパイルした際に、特定のコンパイルエラーが発生することを期待するテストを示していました。
これらのキーワードは、testlib
によって内部的に解釈され、対応するGoコンパイラやリンカのコマンド、および実行ロジックが呼び出されます。これにより、テストの記述者は、テストの目的をより明確に表現できるようになり、テストスクリプトの複雑さが大幅に軽減されます。
関連リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/8080384a68850b47d7c5a85f7f904de80a3ae449
- Go Code Review: https://golang.org/cl/5656083
参考にした情報源リンク
- Go testlib purpose: https://speedscale.com/blog/go-testing-frameworks/
- Go test magic comments (Build Tags): https://mickey.dev/blog/go-build-tags/
- Go test magic comments (Example Functions): https://go.dev/blog/examples
- Go test magic comments (Compiler Directives): https://medium.com/@vladimir.vivien/go-compiler-directives-and-how-they-work-a7222374777d