Goで簡単な関数を実装しながらgo testを理解する

この記事は[tomowarkar ひとりAdvent Calendar 2019](https://qiita.com/advent-calendar/2019/tomowarkar)の3日目の記事です。

今日はgo testを理解していきます。

# 今回実装する関数
整数配列から最小値を求める関数をそれぞれ実装していきます。
pythonでいう`min`関数ですね。

```bash

$ python
>>> min([1,2,3])
1
```
# testingパッケージについて
- Goでのテストはtestingパッケージを使う。
- テストは`{filename}_test.go`というファイルで作成。
- テストのメソッドは命名則があるので注意(以下引用)。

>func TestXxx（* testing.T）
ここで、Xxxは小文字で始まっていません。関数名は、テストルーチンを識別するのに役立ちます。
[Package testing](https://golang.org/pkg/testing/)

### テストファイルを同時に作成する
テストを書く場合は同時に作成してしまうと楽そうです。

```bash
$ touch math{,_test}.go
$ ls
math.go math_test.go
```

# テストを書く
それでは上記で作成した`mathファイル`にコードを書いていきます。TDD的にまずはテストから。

- テーブルを使ってテストを実装
- `min`関数は`minInt`として実装
- [サブテスト](https://golang.org/pkg/testing/#hdr-Subtests_and_Sub_benchmarks) を使ってテストケース毎にテストを分類

```math_test.go
package math

import (
	"testing"
)

func TestMinInt(t *testing.T) {
	tests := []struct {
		name string
		in   []int
		want int
	}{
		{"natural_number_slice", []int{1, 2, 3}, 1},
		{"nega_posi", []int{-1, 0}, -1},
		{"nega_nega", []int{-10, -11}, -11},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := minInt(tt.in)
			if got != tt.want {
				t.Fatalf("want %v but %v", tt.want, got)
			}
		})
	}
}
```
```math.go
package math

func minInt(slice []int) int {
	var min int
	return min
}
```
### 失敗することを確認
まだminIntを実装しておらずただ0を返すだけの関数なので、テストは当然落ちます。

```bash
$ go test
--- FAIL: TestMinInt (0.00s)
    --- FAIL: TestMinInt/natural_number_slice (0.00s)
        math_test.go:21: want 1 but 0
    --- FAIL: TestMinInt/nega_posi (0.00s)
        math_test.go:21: want -1 but 0
    --- FAIL: TestMinInt/nega_nega (0.00s)
        math_test.go:21: want -11 but 0
FAIL
exit status 1
FAIL    math       0.006s
```
一つ目のテスト結果をみてみます

```bash

    --- FAIL: TestMinInt/natural_number_slice (0.00s)
        math_test.go:21: want 1 but 0
```
データオブジェクトは`{"natural_number_slice", []int{1, 2, 3}, 1}`で、テストログの`want 1 but 0`より1が期待されたけれども、得られたのは0ですよといことがわかる。

# 関数を実装する
テストが落ちることが確認できたので関数を実装します。簡単ですね。

```math.go
package math

func minInt(slice []int) int {
	var min int = slice[0]
	for _, value := range slice {
		if min > value {
			min = value
		}
	}
	return min
}
```
### 成功することを確認する
関数を実装したので期待通りに動作することを確認します。

```bash
$ go test
PASS
ok      math       0.005s
```
### テストの途中経過を確認する
PASSと出ているだけではどのテストを確認したのかわからないため、テストの途中経過を確認したくなりました。
そのような場合は`-v`オプションを追加します。

TestMinIntの3つのサブテストを確認した結果PASSになっているのが分かります。

```bash
$ go test -v
=== RUN   TestMinInt
=== RUN   TestMinInt/natural_number_slice
=== RUN   TestMinInt/nega_posi
=== RUN   TestMinInt/nega_nega
--- PASS: TestMinInt (0.00s)
    --- PASS: TestMinInt/natural_number_slice (0.00s)
    --- PASS: TestMinInt/nega_posi (0.00s)
    --- PASS: TestMinInt/nega_nega (0.00s)
PASS
ok      math       0.006s
```
### 各関数, サブテスト毎にテスト結果を確認する
今回はTestMinIntしかテスト対象がないため必要としませんが、`-run {your_test_method}`オプションで各メソッド毎にテスト結果を確認することができます。

```bash
$ go test -run TestMinInt
```
また同様にして`-run {your_test_method/sub_test}`オプションを使ってサブテスト毎にテスト結果を確認することもできます。

```bash
$ go test -v -run TestMinInt/natural_number_slic
=== RUN   TestMinInt
=== RUN   TestMinInt/natural_number_slice
--- PASS: TestMinInt (0.00s)
    --- PASS: TestMinInt/natural_number_slice (0.00s)
PASS
ok      math       0.005s
```
### テストカバレッジを確認する
最後に`-cover`オプションを使ってテストカバレッジを確認します。

```bash

$ go test -cover
PASS
coverage: 100.0% of statements
ok      math       0.005s
```
### 参考記事
https://golang.org/pkg/testing/

https://budougumi0617.github.io/2018/08/19/go-testing2018/
# まとめ
- go testの書き方がわかった
- go testの各オプションの理解ができた
- テストカバレッジ上げていこう

以上明日も頑張ります！！
[tomowarkar ひとりAdvent Calendar Advent Calendar 2019](https://qiita.com/advent-calendar/2019/tomowarkar)