ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
…
パフォーマンス テスト システムは、テスト担当者がパフォーマンスの問題を分析するのに役立つコード パフォーマンス データを提供できます。
ヒント
単体テストとは、ソフトウェア内のテスト可能な最小単位をチェックおよび検証することを指します。単体テストにおけるユニットの意味は、C言語のユニットは関数、 Javaのユニットはクラス、ウィンドウなど、実際の状況に応じて具体的に判断する必要があるのが一般的です。またはグラフィック ソフトウェアのメニュー。一般に、ユニットとは人為的に指定されたテスト対象の最小の機能モジュールです。
単体テストは、ソフトウェア開発中に実行される最低レベルのテスト作業であり、ソフトウェアの独立したユニットがプログラムの残りの部分から分離されてテストされます。
単体テスト – コードをテストおよび検証するためのフレームワーク
単体テストを開始するには go のソースコードファイルを用意する必要があり、ファイル名を付ける際には_test
で終わるようにする必要があります。デフォルトでは、 go test
コマンドにはパラメータは必要ありません。ソース パッケージ内のすべてのテスト ファイルが自動的にテストされます。もちろん、パラメータを指定することもできます。
よく使用されるパラメーターをいくつか示します。
- -bench regexp は、対応するベンチマークを実行します (例: -bench=.;)。
- -cover テスト カバレッジをオンにします。
- -run regexp は、regexp に一致する関数のみを実行します。たとえば、-run=Array は、配列の先頭を含む関数を実行します。
- -v テスト用の詳細なコマンドを表示します。
単体テストのソース コード ファイルは複数のテスト ケースで構成されている場合があり、各テスト ケース関数にはTest
プレフィックスを付ける必要があります。次に例を示します。
func TestXXX( t *testing.T )
- テスト ケース ファイルは通常のソース コードのコンパイルには参加せず、実行可能ファイルには含まれません。
- テスト ケース ファイルは
go test
コマンドを使用して実行され、関数エントリとして main() は必要ありません。ソース コード内のTest
で始まり_test
で終わる関数はすべて自動的に実行されます。 - テスト ケースが *testing.T パラメーターに渡されない可能性があります。
helloworld のテスト コード (具体的な場所は./src/gotest/helloworld_test.go
です):
package gotest
import "testing"
func TestHelloWorld(t *testing.T) {
t.Log("hello world")
}
コードの説明は次のとおりです。
- 5 行目では、単体テスト ファイル (*_test.go) のテスト エントリは Test で始まる必要があり、パラメーターは *testing.T の関数です。単体テスト ファイルには複数のテスト エントリを含めることができます。
- 6 行目では、テスト パッケージの T 構造体によって提供される Log() メソッドを使用して文字列を出力します。
1) 単体テストのコマンドライン
単体テストは go test コマンドで開始します。例:
$ go test helloworld_test.go
ok command-line-arguments 0.003秒
$ go test -v helloworld_test.go
=== RUN TestHelloWorld
--- PASS: TestHelloWorld (0.00秒)
helloworld_test.go:8: hello world
PASS
ok command-line-arguments 0.004秒
コードの説明は次のとおりです。
- go test の後に helloworld_test.go ファイルが続く 1 行目は、このファイル内のすべてのテスト ケースをテストすることを意味します。
- 行 2 はテスト結果を表示します。ok はテストに合格したことを意味し、command-line-arguments はテスト ケースで使用する必要があるパッケージ名、0.003 秒はテストにかかった時間を意味します。
- 3 行目は、追加パラメータに
-v
が追加されていることを示しており、テスト中の詳細なプロセスを表示できます。 - 4 行目は、TestHelloWorld という名前のテスト ケースの実行を開始することを意味します。
- 5 行目は TestHelloWorld テスト ケースが実行されたことを示し、PASS はテストが成功したことを示します。
- 6 行目は文字列 hello world を出力します。
2) 指定された単体テスト ケースを実行します。
go test
でファイルを指定すると、デフォルトでファイル内のすべてのテスト ケースが実行されます。 -run
パラメーターを使用すると、必要なテスト ケースを選択して個別に実行できます。次のコードを参照してください。
ファイルには複数のテスト ケースが含まれています (特定の場所は./src/gotest/select_test.go
です)。
ここでは TestA がテスト用に指定されています。
$ go test -v -run TestA select_test.go
=== 実行 TestA
--- 合格: TestA (0.00秒)
select_test.go:6: A
=== 実行 TestAK
--- 合格: TestAK (0.00秒)
select_test.go:10: AK
PASS
ok command-line-arguments 0.003秒
TestA と TestAK の両方のテスト ケースが実行されます。これは、 -run
が後に続くテスト ケースの名前が正規表現をサポートしており、 -run TestA$
を使用して実行できるのは TestA テスト ケースのみであるためです。
3) 単体テストの結果をマークする
現在のテスト ケースを終了する必要がある場合は、FailNow を使用できます。次のコードを参照してください。
テスト結果マーク (具体的な場所は./src/gotest/fail_test.go
)
func TestFailNow(t *testing.T) {
t.FailNow()
}
テストを終了せずにエラーのみをマークする方法もあります。コードは次のとおりです。
func TestFail(t *testing.T) {
fmt.Println("失敗前")
t.Fail()
fmt.Println("失敗後")
}
テスト結果は次のとおりです。
=== 実行中 TestFail
失敗前
失敗後
--- 失敗: TestFail (0.00s)
失敗
終了ステータス 1
FAIL command-line-arguments 0.002s
ログから、5 行目で Fail() を呼び出した後、テスト結果が失敗としてマークされていますが、7 行目はまだプログラムによって実行されていることがわかります。
4) 単体テストログ
各テスト ケースは同時に実行でき、testing.T によって提供されるログ出力を使用すると、ログがテスト コンテキストとともに確実に出力されます。 testing.T にはいくつかのログ出力メソッドが用意されています。詳細については、次の表を参照してください。
方法 | 述べる |
---|---|
Log | ログを出力し、同時にテストを終了します |
Logf | ログをフォーマットして印刷し、同時にテストを終了します |
Error | エラーログを出力し、同時にテストを終了します |
Errorf | エラーログをフォーマットして印刷し、同時にテストを終了します |
Fatal | 致命的なログを出力し、同時にテストを終了します |
Fatalf | 致命的なログをフォーマットして出力し、同時にテストを終了します |
開発者は、実際のニーズに応じて適切なログを選択できます。
ベンチマーク – コードのメモリ使用量と実行時の効率に関するパフォーマンス データを取得します。
ベンチマーク テストでは、プログラムの実行パフォーマンスと CPU 消費の程度をテストできます。ベンチマークテストフレームワークはGo言語で提供されており、単体テストと同様の利用方法となっており、高精度タイマーや各種解析ツールをユーザーが用意する必要がなく、ベンチマークテスト自体は非常に標準的なテストレポートを出力することができます。
1) 基本テストの基本的な使い方
ベンチマークの基本的な使用法を理解するために例を使用してみましょう。
ベンチマーク テスト (具体的な場所は./src/gotest/benchmark_test.go
)
package gotest
import "testing"
func Benchmark_Add(b *testing.B) {
var n int
for i := 0; i < b.N; i++ {
n++
}
}
このコードは、ベンチマーク フレームワークを使用して追加のパフォーマンスをテストします。行 7 の bN は、ベンチマーク フレームワークによって提供されます。テスト コードは、関数の再入性とステートレス性を保証する必要があります。つまり、テスト コードは、グローバル変数などのメモリ プロパティを持つデータ構造を使用しません。同じコードを複数回実行するときに環境の不整合を避けるために、N 値の範囲を想定することはできません。
次のコマンド ラインでベンチマークを開始します。
$ go test -v -bench=. benchmark_test.go
goos: linux
goarch: amd64
Benchmark_Add-4 20000000 0.33 ns/op
PASS
ok command-line-arguments 0.700s
コードの説明は次のとおりです。
- 1 行目の
-bench=.
benchmark_test.go ファイル内のすべてのベンチマーク テストを実行することを意味し、単体テストの-run
と同様です。 - ベンチマーク テストの名前は 4 行目に表示され、2000000000 はテストの数を表します。これは testing.B 構造体のプログラムに提供される N です。 「0.33 ns/op」は、各操作にかかる時間 (ナノ秒) を示します。
注: Windows で go test コマンド ラインを使用する場合、 -bench=.
-bench="."
として記述する必要があります。
2) ベンチマークの原則
ベンチマーク フレームワークのテスト ケースのデフォルトのテスト時間は 1 秒です。テストの開始時、Benchmark で始まるベンチマーク テスト ケース関数が 1 秒未満を返すと、testing.B の N 値は 1、2、5、10、20、50… ずつ増加し、インクリメント後の同じ時間、値の値はベンチマーク テスト ケース関数を再呼び出しします。
3) カスタムテスト時間
テスト時間は、 -benchtime
パラメーターを使用してカスタマイズできます。次に例を示します。
$ go test -v -bench=. -benchtime=5s benchmark_test.go
goos: linux
goarch: amd64
ベンチマーク_Add-4 10000000000 0.33 ns/op
PASS
ok command-line-arguments 3.380s
4) テストメモリ
ベンチマーク テストでは、コード部分のメモリ割り当ての可能性をカウントできます。以下は文字列でフォーマットされた関数であり、一部の割り当て操作は内部で実行されます。
func Benchmark_Alloc(b *testing.B) {
for i := 0; i < b.N; i++ {
fmt.Sprintf("%d", i)
}
}
-benchmem
パラメータをコマンド ラインに追加してメモリ割り当てを表示します。次のコマンドを参照してください。
$ go test -v -bench=Alloc -benchmem benchmark_test.go
goos: linux
goarch: amd64
Benchmark_Alloc-4 20000000 109 ns/op 16 B/op 2 allocs/op
PASS
ok command-line-arguments 2.311s
コードの説明は次のとおりです。
- 1 行目のコードでは、
-bench
後に Alloc が追加され、 Benchmark_Alloc() 関数のみがテストされることを指定しています。 - コードの 4 行目の「16 B/op」は、各呼び出しに 16 バイトを割り当てる必要があることを意味し、「2 allocs/op」は、各呼び出しに 2 つの割り当てがあることを意味します。
この情報に基づいて、開発者は最適化と調整のための可能な割り当てポイントを迅速に見つけることができます。
5) 制御タイマー
一部のテストでは、ある程度の起動時間と初期化時間が必要であり、Benchmark() 関数からのタイミングがテスト結果の精度に大きく影響します。 testing.B は、必要な間隔でのみタイマーをテストできるように、タイマーを便利に制御するための一連のメソッドを提供します。タイマーの制御を理解するために次のコードを使用します。
ベンチマーク テストのタイマー コントロール (特定の場所は./src/gotest/benchmark_test.go
です):
func Benchmark_Add_TimerControl(b *testing.B) {
// タイマーをリセットする
b.ResetTimer()
// タイマーを停止する
b.StopTimer()
// タイマーを開始する
b.StartTimer()
var n int
for i := 0; i < b.N; i++ {
n++
}
}
Benchmark() 関数から、タイマーのカウントが開始されます。 StopTimer() は、このカウント プロセスを停止し、時間のかかる操作を実行し、StartTimer() を通じてタイミングを再開できます。 ResetTimer() はカウンターのデータをリセットできます。
カウンタには、時間のかかるデータだけでなく、メモリ割り当てデータも含まれます。