Go言語の単体テストコードの書き方をまとめます。
単体テストは、コードの品質を保つ上で非常に重要です。世界的に見れば、「テストコードのないコードは、見る価値もないコード」とされているくらいです。
<目次>
参考
単体テストの基本
まずは、以下のフォルダとファイルを作成しましょう。
1 2 3 4 |
mkdir -p utils/sort touch utils/sort/sort.go touch utils/sort/sort_test.go cd utils/sort/ |
プロダクトファイル(sort.go)とテストファイル(sort_test.go)を同階層に置いています。
プロダクトファイルには、要素の並び替えの処理を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// sort.go package sort // BubbleSort - sorts elements func BubbleSort(elements []int) { keepWorking := true for keepWorking { keepWorking = false for i := 0; i < len(elements)-1; i++ { if elements[i] < elements[i+1] { keepWorking = true elements[i], elements[i+1] = elements[i+1], elements[i] } } } } |
テストファイルには、「testingパッケージ」を用いて、テストコードを記述していきます。
1 2 3 4 5 6 |
// sort_test.go package sort import "testing" func TestBubbleSortOrderDESC(t *testing.T) {} |
テスト関数は、「TestXXXX」となるように先頭にTestとつけましょう。また、引数には、「testing.T」引数を持ちます。
次に、テストコードを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// sort_test.go package sort import "testing" func TestBubbleSortOrderDESC(t *testing.T) { // Init elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} // Execution BubbleSort(elements) // Validation if elements[0] != 9 { t.Error("first element should be 9") } if elements[len(elements)-1] != 0 { t.Error("last elements should be 0") } } |
わかりやすさのレベルでしかないのですが、「Init」、「Execution」、「Validation」の3つのセクションを設けています。
Init・・・初期データ準備エリア
Execution ・・・ テスト対象関数実行エリア
Validation ・・・ 検証エリア
これは、決まりではありません。一つの方法です。
terminal上から「go test」コマンドを実行するとテストができます。
1 2 3 4 5 6 7 |
// テストファイル格納ディレクトリ上 go test // 全てのテストコードを実行する go test ./... ok github.com/hoge/golang-testing/utils/sort 0.011s |
カバレッジ
「-cover」オプションをつけてコマンドを実行すると「テストの包括率」が表示されます。
実装したコードに対して、どの程度の割合でテストができているか示す指標の様なものです。
1 2 3 4 |
go test -cover PASS coverage: 100.0% of statements <<< カバレッジ ok github.com/hoge/golang-testing/utils/sort 0.023s |
現時点では、カバレッジ100%になっています。
統合テスト
異なるレイヤーのUnit Testを統合的にテストする、それが統合テストです。
「api」フォルダを作成して、utilsフォルダをapiフォルダ配下に格納しましょう。
1 2 3 4 5 |
api └── utils └── sort ├── sort.go └── sort_test.go |
続いて、api配下に「services」フォルダを作成し、sort_service.goファイルを作成します。
1 2 3 |
$ mkdir api/services $ touch api/services/sort_service.go $ touch api/services/sort_service_test.go |
このsort_service.goには、ビジネスロジックを記述します。
そして、sort_service_test.goには、sort.goとsort_service.goの統合的なテストを書きます。

1 2 3 4 5 6 7 8 9 |
// sort_service.go package services import "github.com/hoge/golang-testing/api/utils/sort" func Sort(elements []int) { sort.BubbleSort(elements) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// sort_service_test.go package services import "testing" func TestSort(t *testing.T) { // Init elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} // Execution Sort(elements) // Validation if elements[0] != 9 { t.Error("first element should be 9") } if elements[len(elements)-1] != 0 { t.Error("last elements should be 0") } } |
sort_test.goと同じ検証(Validation)をしていますが、ひとまずテストを実行します。
1 2 3 4 |
$ go test -cover PASS coverage: 100.0% of statements ok github.com/hoge/golang-testing/api/services 0.033s |
OKですね。
ベンチマーク
ベンチマークとは、ソフトウェアの処理性能を定量的に評価するための基準となるテストを指します。
実は、Go言語にはSort関数が既に組み込まれています。
このSort関数を基準に、私たちが実装したSort関数の性能をテストしてみましょう。
sort.goにSort関数を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// sort.go package sort import "sort" // BubbleSort - sorts elements func BubbleSort(elements []int) { keepWorking := true for keepWorking { keepWorking = false for i := 0; i < len(elements)-1; i++ { // < -> >に変更 if elements[i] > elements[i+1] { keepWorking = true elements[i], elements[i+1] = elements[i+1], elements[i] } } } } // Goの組み込み関数 func Sort(elements []int) { sort.Ints(elements) } |
続いて、sort_tests.goのテストコードを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// sort_test.go package sort import ( "testing" ) func TestBubbleSortIncresingOrder(t *testing.T) { // Init elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} // Execution BubbleSort(elements) // Validation if elements[0] != 0 { t.Error("first element should be 0") } if elements[len(elements)-1] != 9 { t.Error("last elements should be 9") } } func TestSortIncresingOrder(t *testing.T) { // Init elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} // Execution Sort(elements) // Validation if elements[0] != 0 { t.Error("first element should be 0") } if elements[len(elements)-1] != 9 { t.Error("last elements should be 9") } } |
テストを実行してみましょう。
1 2 |
go test ./... ok github.com/hoge/golang-testing/api/utils/sort 0.041s |
テストは無事にPassした様ですね。
ベンチマークを測る時は、testingパッケージの「*testing.B」を利用します。
1 2 3 4 5 6 7 8 9 10 |
// sort_tests.go func BenchmarkBubbleSort(b *testing.B) { elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} for i := 0; i < b.N; i++ { BubbleSort(elements) } } |
ベンチマークテストを実行したい場合は、「-bench」オプションを付与します。
1 |
$ go test -bench . |
また、Visual Studio Codeで、GoのExtensionを導入している場合は、Visual Studio Code上で実行できます。※run benchmarkを押下します

1 |
BenchmarkBubbleSort-4 100000000 11.3 ns/op 0 B/op 0 allocs/op |
上記ですが、ループあたり11.3 nsの速度でループが10000000回実行されたことを意味します。3回実行しておきましょう。
1 2 3 |
BenchmarkBubbleSort-4 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkBubbleSort-4 100000000 10.3 ns/op 0 B/op 0 allocs/op BenchmarkBubbleSort-4 100000000 10.3 ns/op 0 B/op 0 allocs/op |
Go言語の組み込みSort関数の方もBenchmark関数を作成します。
1 2 3 4 5 6 7 8 |
func BenchmarkSort(b *testing.B) { elements := []int{5, 2, 3, 1, 6, 7, 9, 0, 4, 8} for i := 0; i < b.N; i++ { Sort(elements) } } |
1 2 3 |
BenchmarkSort-4 11138256 92.4 ns/op 32 B/op 1 allocs/o BenchmarkSort-4 12283944 97.5 ns/op 32 B/op 1 allocs/op BenchmarkSort-4 12569583 95.9 ns/op 32 B/op 1 allocs/op |
まとめ
今回は、Go言語のテストの実行方法、カバレッジおよび統合テストについての概略、ベンチマークの実装・実行方法について解説しました。
次回は、REST APIのテストコードについて解説していきたいと思います。
コメントを残す
コメントを投稿するにはログインしてください。