Goのtestingパッケージの基本を理解する

[テックタッチアドベントカレンダー](https://qiita.com/smith-30/items/3fd1457b5c16296bdccd)11日目を担当する [@taisa831](https://qiita.com/taisa831) です。10日目は [@mxxxxkxxxx](https://qiita.com/mxxxxkxxxx) の[「Go言語　ElastiCacheの　その前に」](https://qiita.com/mxxxxkxxxx/items/a4e526d5b52393668a79)でした。575 の 5 が Go に掛かっていていい感じですね！もちろん内容も良い！

本記事では、`Go`の`testing`パッケージについて書きます。既存記事を調べてみると、そこそこあるけどそこまで多くはない。重厚な記事もあればあっさりした記事もある。ということで深すぎず浅すぎずを目指そうと思います。

「testing パッケージの基本を理解する」なので`Go`の [testing パッケージ](https://github.com/golang/go/tree/master/src/testing) を参考にしました。テストに関しては最初アサーションがないことに戸惑いましたが、慣れたらない方がよく感じてきました。執筆時点でのバージョンは`go1.13.4`です。

- [もっともシンプルなテスト](#もっともシンプルなテスト)
    - [パッケージ/ファイル単位でテスト対象を指定する](#パッケージファイル単位でテスト対象を指定する)
- [Benchmark を取る](#benchmarkを取る)
    - [一部の処理だけ Benchmark を取る](#一部の処理だけbenchmarkを取る)
- [Example テスト](#exampleテスト)
    - [Output:](#output)
    - [Unorderd output:](#unorderd-output)
    - [GoDoc に Example を出力してみる](#godocにexampleを出力してみる)
- [カバレッジをとる](#カバレッジをとる)
- [テストをスキップする](#テストをスキップする)
- [サブテストとサブベンチマーク](#サブテストとサブベンチマーク)
    - [サブテストをパラレルに実行する](#サブテストをパラレルに実行する)
    - [-run オプションでテスト対象を絞る](#-runオプションでテスト対象を絞る)
- [共通処理のエラー箇所を分かりやすく出力する](#共通処理のエラー箇所を分かりやすく出力する)
- [前処理/後処理をする](#前処理後処理をする)
- [その他](#その他)
- [おわりに](#おわりに)


## もっともシンプルなテスト

`Go`でテストを実行するにはいくつかルールがあります。

- ファイル名は`**_test.go`とする
- 関数は`TestCamelCase`のように`Test`ではじめ後ろは`CamelCase`とする
- `testing`パッケージを引数で受ける
- テストファイルはテスト対象ファイルと同一パッケージとする（※テストだけ例外的に`packagename_test`とすることも可能）

そして下記のように期待値と実行時の値が違う場合は`t.Errorf`でエラーを記録します（後述しますが必ずしも`t.Errorf`である必要はありません）。

```go
func TestAbs(t *testing.T) {
	got := math.Abs(-1)
	if got != 1 {
		t.Errorf("Abs(-1) = %f; want 1", got)
	}
}
```

```sh:実行
$ go test
ok  	command-line-arguments	4.018s
```

`-v`オプションをつけることでより詳細な情報が見られます。

```sh:実行
go test -v
=== RUN   TestAbs
--- PASS: TestAbs (0.00s)
PASS
ok  	command-line-arguments	0.005s
```

### パッケージ/ファイル単位でテスト対象を指定する

パッケージ単位でテスト対象を指定するには以下のようにコマンドを使い分けます。

```sh
# カレントディレクトリ
$ go test 

# カレント配下全て
$ go test ./...

# testing パッケージ配下
$ go test testing

# testing/quick パッケージ配下
$ go test testing/quick

# testing 配下全て
$ go test testing/...

# 同じパッケージがテストが対象の場合
$ go test testing_testing.go testing.go

# packgename_test のようにパッケージを分けている場合
$ go test testing_testing.go
```

## `Benchmark`を取る

`testing`パッケージを使って`Benchmark`を取ることもできます。`Benchmark`を取るには`*testing.B`を使い、`-bench`オプションを指定して実行します。

```go
func BenchmarkHello(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fmt.Sprintf("hello")
	}
}
```

以下の実行時のベンチマークは`21,764,674 times at a speed of 54.1 ns per loop`となります。

```sh:実行
$ go test -bench=.
goos: darwin
goarch: amd64
pkg: github.com/taisa831/sandbox-go/testing
BenchmarkHello-8   	21764674	        54.1 ns/op
PASS
ok  	github.com/taisa831/sandbox-go/testing	1.241s
```

### 一部の処理だけ`Benchmark`を取る

`Benchmark`には`StartTimer()`、`StopTime()`、`ResetTimer()`が用意されています。これらを利用して一部の処理だけピンポイントでベンチマークをとることもできます。

```go
func BenchmarkBig(b *testing.B) {
	// 重い処理
	Big()
	// リセット
	b.ResetTimer()
	// ここから計測が始まる
	for i := 0; i < b.N; i++ {
		fmt.Sprintf("hello")
	}
}
```

重い処理は無視して先ほどと同じような結果となるベンチマークが取れました。

```sh:実行
go test -bench=.
goos: darwin
goarch: amd64
pkg: github.com/taisa831/sandbox-go/testing
BenchmarkBig-8   	22457809	        54.2 ns/op
PASS
ok  	github.com/taisa831/sandbox-go/testing	14.274s
```

## `Example`テスト

`testing`パッケージには少し特殊なものとして出力をテストする`Example`テスト機能があります。`Example`テストは`**_test.go`内で実行することができます。出力をチェックするには`Output:`や`Unordered output:`を利用します。

### Output:

`Output: hello`と書くことでテストができます。例えば`Output: helle`に変えるとテストでエラーとなります。

```go 
func ExampleHello() {
	fmt.Println("hello")
	// Output: hello
}
```

```sh:実行
go test -v
=== RUN   ExampleHello
--- PASS: ExampleHello (0.00s)
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

複数行出力した結果のテストも可能です。

```go 
func ExampleSalutations() {
	fmt.Println("hello, and")
	fmt.Println("goodbye")
	// Output:
	// hello, and
	// goodbye
}
```

```sh:実行
go test -v
=== RUN   ExampleSalutations
--- PASS: ExampleSalutations (0.00s)
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

### Unorderd output:

`Unordered output`はその名の通りオーダーを無視して出力を検証してくれます。

```go
func ExamplePerm() {
	for _, value := range rand.Perm(5) {
		fmt.Println(value)
	}
	// Unordered output: 4
	// 2
	// 1
	// 3
	// 0
}
```

```sh:実行
go test -v
=== RUN   ExamplePerm
--- PASS: ExamplePerm (0.00s)
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

`Example`テストは`GoDoc`にも利用でき、下記のような命名規則があります。

- func Example() { ... }
    - `GoDoc`の`Package`に出る
- func ExampleF() { ... }
    - `GoDoc`の`Function`に出る
- func ExampleT() { ... }
    - `GoDoc`の`Type`に出る
- func ExampleT_M() { ... }
    - `GoDoc`の`Type`の`Method`に出る

更に上記の単位で細かく`Example`テストを分けて書きたい場合は`_suffix`のように小文字で記述します。

- func Example_suffix() { ... }
- func ExampleF_suffix() { ... }
- func ExampleT_suffix() { ... }
- func ExampleT_M_suffix() { ... }

### `GoDoc`に`Example`を出力してみる

実際にどのように`GoDoc`に出るかイメージしにくいのでサンプルを作成して確認してみます。ここまではテストファイルしかなかったので、別途サンプル実装とテストを書いて実行してみました。

```go:person.go
// Package person
package person

type Person struct {
	firstName string
	lastName  string
}

// NewPerson
func NewPerson(firstName string, LastName string) *Person {
	return &Person{firstName: firstName, lastName: LastName}
}

// GetFirstName
func (p *Person) GetFirstName() string {
	return p.firstName
}

// GetLastName
func (p *Person) GetLastName() string {
	return p.lastName
}
```

```go:person_test.go
func Example() {
	person := NewPerson("Taro", "Yamada")
	fmt.Println(person.GetFirstName())
	// output: Taro
}

func ExampleNewPerson() {
	person := NewPerson("Taro", "Yamada")
	fmt.Println(person.GetFirstName())
	// output: Taro
}

func ExamplePerson_GetFirstName() {
	person := NewPerson("Taro", "Yamada")
	fmt.Println(person.GetFirstName())
	// output: Taro
}

func ExamplePerson_GetLastName() {
	person := NewPerson("Taro", "Yamada")
	fmt.Println(person.GetLastName())
	// output: Yamada
}
```

上記サンプルコードを`GoDoc`に出力してみます。`GoDoc`が入っていない場合は`go get`してからコマンドを実行し`localhost:6060`にアクセスします。`Packages`にアクセスすると自分のパッケージ情報が見られます。

```sh
$ go get golang.org/x/tools/cmd/godoc
$ godoc -http=:6060
# localhost:6060にアクセス
```

- **`Example()`は`Package`に表示される**

<img width="772" alt="スクリーンショット 2019-12-11 11.28.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36984/ab78cc4b-25b2-87d5-3679-363a83abb532.png">

- **`ExampleNewPerson()`は`Type`に表示される**

<img width="772" alt="スクリーンショット 2019-12-11 11.29.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36984/77eee140-10be-3205-55e7-995f04774f03.png">

- **`ExamplePerson_GetFirstName()`と`ExamplePerson_GetLastName`は`func`に表示される**

<img width="752" alt="スクリーンショット 2019-12-11 11.29.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36984/0e0219be-3ca7-6e7d-205d-66191a021820.png">

<img width="663" alt="スクリーンショット 2019-12-11 11.29.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36984/5b7dfd8c-ad24-9f03-e875-0304056d6693.png">


## カバレッジをとる

上記サンプルにテストを追加しカバレッジをとってみます。カバレッジは`-cover`オプションで簡単にみることができます。ちなみに`Example`テストだけでもカバレッジが出るようです。

```sh:実行
go test -v -cover
=== RUN   Example
--- PASS: Example (0.00s)
=== RUN   ExampleNewPerson
--- PASS: ExampleNewPerson (0.00s)
=== RUN   ExamplePerson_GetFirstName
--- PASS: ExamplePerson_GetFirstName (0.00s)
=== RUN   ExamplePerson_GetLastName
--- PASS: ExamplePerson_GetLastName (0.00s)
PASS
coverage: 100.0% of statements
ok  	github.com/taisa831/sandbox-go-impl/person	0.005s
```

`Example`テストだけだと中途半端感があるので通常のテストに変えてみます。好みもあると思いますが`Goland`や`VSCode`の機能を使うと簡単にテストコードの枠組みが出力できるのでかなり楽にテストが作成できます。

```go
func TestNewPerson(t *testing.T) {
	type args struct {
		firstName string
		LastName  string
	}
	tests := []struct {
		name string
		args args
		want *Person
	}{
		{
			"NewPerson",
			args{"Taro", "Yamada"},
			&Person{firstName: "Taro", lastName: "Yamada"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := NewPerson(tt.args.firstName, tt.args.LastName); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewPerson() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestPerson_GetFirstName(t *testing.T) {
	type fields struct {
		FirstName string
		LastName  string
	}
	tests := []struct {
		name   string
		fields fields
		want   string
	}{
		{
			"GetFirstName",
			fields{FirstName:"Taro", LastName:"Yamada"},
			"Taro",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := &Person{
				firstName: tt.fields.FirstName,
				lastName:  tt.fields.LastName,
			}
			if got := p.GetFirstName(); got != tt.want {
				t.Errorf("GetFirstName() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestPerson_GetLastName(t *testing.T) {
	type fields struct {
		FirstName string
		LastName  string
	}
	tests := []struct {
		name   string
		fields fields
		want   string
	}{
		{
			"GetLastName",
			fields{FirstName:"Taro", LastName:"Yamada"},
			"Yamada",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := &Person{
				firstName: tt.fields.FirstName,
				lastName:  tt.fields.LastName,
			}
			if got := p.GetLastName(); got != tt.want {
				t.Errorf("GetLastName() = %v, want %v", got, tt.want)
			}
		})
	}
}

```

同じようにカバレッジが出せました。

```sh:実行
go test -v -cover
=== RUN   TestNewPerson
=== RUN   TestNewPerson/NewPerson
--- PASS: TestNewPerson (0.00s)
    --- PASS: TestNewPerson/NewPerson (0.00s)
=== RUN   TestPerson_GetFirstName
=== RUN   TestPerson_GetFirstName/GetFirstName
--- PASS: TestPerson_GetFirstName (0.00s)
    --- PASS: TestPerson_GetFirstName/GetFirstName (0.00s)
=== RUN   TestPerson_GetLastName
=== RUN   TestPerson_GetLastName/GetLastName
--- PASS: TestPerson_GetLastName (0.00s)
    --- PASS: TestPerson_GetLastName/GetLastName (0.00s)
PASS
coverage: 100.0% of statements
ok  	github.com/taisa831/sandbox-go-impl/person	0.006s
```

どこのコードをテストが通っているかを確認したい場合には`html`に変換して確認することももちろんできます。

```sh:実行
$ go test -coverprofile=cover.out
PASS
coverage: 100.0% of statements
ok  	github.com/taisa831/sandbox-go-impl/person	0.006s

$ go tool cover -html=cover.out -o cover.html
$ open cover.html
```

HTML出力結果

<img width="731" alt="スクリーンショット 2019-12-11 13.32.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36984/c469beba-b14f-2c5a-02f8-6dbe47461dcd.png">

## テストをスキップする

下記の例では`--short`オプションと組み合わせて使っていますが、実行すると`testing.Short()`が`true`となりスキップされます。ショートモードではこのテストは実行不要だという時などに使います。

```go 
func TestTimeConsuming(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}
}
```

```sh:実行
go test --short -v
=== RUN   TestTimeConsuming
--- SKIP: TestTimeConsuming (0.00s)
    testing_test.go:78: skipping test in short mode.
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

似た用途のメソッドは`tesing`パッケージの`TB`インターフェースに定義されているのであげておきます。基本的には`Error`や`Errorf`を使うことが多いと思います。

- Error(args ...interface{})
    - ログを出力してエラーをマークする
- Errorf(format string, args ...interface{})
    - フォーマットログを出力してエラーをマークする
- Fail()
    - テストにエラーをマークする
- FailNow()
    - テストにエラーをマークしてそのテストを終了する
- Failed() bool
    - テストがエラーかをチェックする
- Fatal(args ...interface{})
    - エラーを出力してそのテストを終了する
- Fatalf(format string, args ...interface{})
    - フォーマットエラーを出力してそのテストを終了する
- Log(args ...interface{})
    - ログを出力する
- Logf(format string, args ...interface{})
    - フォーマットログを出力する
- Skip(args ...interface{})
    - ログを出力してスキップをマークしてそのテストを終了する
- SkipNow()
    - スキップをマークしてそのテストを終了する
- Skipf(format string, args ...interface{})
    - フォーマットログを出力してスキップをマークしてそのテストを終了する
- Skipped() bool
    - テストがスキップかをチェックする

## サブテストとサブベンチマーク

1つのテスト関数にサブテストを追加して複数のテストを実行することができます。ベンチマークも同様に可能です。サブテストがすべて終わるまで`t.Logf("%s", "finished")`は呼ばれないので`teardown`処理を入れることも可能です。

```go 
func TestFoo(t *testing.T) {
	t.Run("A=1", func(t *testing.T) {
		got := math.Abs(-1)
		if got != 1 {
			t.Errorf("Abs(-1) = %f; want 1", got)
		}
	})
	t.Run("A=2", func(t *testing.T) {
		got := math.Abs(-1)
		if got != 1 {
			t.Errorf("Abs(-1) = %f; want 1", got)
		}
	})
	t.Run("B=1", func(t *testing.T) {
		got := math.Abs(-1)
		if got != 1 {
			t.Errorf("Abs(-1) = %f; want 1", got)
		}
	})

	t.Logf("%s", "finished")
	// teardown
}
```

```sh:実行
go test -v --run Foo
=== RUN   TestFoo
=== RUN   TestFoo/A=1
=== RUN   TestFoo/A=2
=== RUN   TestFoo/B=1
--- PASS: TestFoo (0.00s)
    --- PASS: TestFoo/A=1 (0.00s)
    --- PASS: TestFoo/A=2 (0.00s)
    --- PASS: TestFoo/B=1 (0.00s)
    testing_test.go:114: finished
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

### サブテストをパラレルに実行する

サブテスト内で`t.Parallel()`を呼び出すことでサブテストをパラレルに実行することができます。パラレル動作を確認する為に`A-1`テストにだけ`Sleep`を入れて実行してみます。

```go
func TestGroupedParallel(t *testing.T) {
	tests := []struct {
		Name    string
		Want    bool
		WantErr bool
	}{
		{
			Name:    "test1",
			Want:    true,
			WantErr: false,
		},
	}

	for _, tc := range tests {
		tc := tc // capture range variable
		t.Run(tc.Name, func(t *testing.T) {
			t.Run("A=1", func(t *testing.T) {
				t.Parallel()
				got := math.Abs(-1)
				time.Sleep(2 * time.Second)
				if got != 1 {
					t.Errorf("Abs(-1) = %f; want 1", got)
				}
				t.Logf("Len=2: %s", time.Now())
			})
			t.Run("A=2", func(t *testing.T) {
				t.Parallel()
				got := math.Abs(-1)
				if got != 1 {
					t.Errorf("Abs(-1) = %f; want 1", got)
				}
				t.Logf("Len=2: %s", time.Now())
			})
			t.Run("B=1", func(t *testing.T) {
				t.Parallel()
				got := math.Abs(-1)
				if got != 1 {
					t.Errorf("Abs(-1) = %f; want 1", got)
				}
				t.Logf("Len=2: %s", time.Now())
			})
		})
	}

	t.Logf("%s", "finished")
	// teardown
}
```

実行結果を見てみると`A-1`のテストが最後まで残り`finished`が呼ばれているのが分かります。パラレルテストでも全てのテストが終わるまで`finished`が呼ばれないので`teardown`処理をすることができます。

```sh:実行
go test -v
=== RUN   TestGroupedParallel
=== RUN   TestGroupedParallel/test1
=== RUN   TestGroupedParallel/test1/A=1
=== PAUSE TestGroupedParallel/test1/A=1
=== RUN   TestGroupedParallel/test1/A=2
=== PAUSE TestGroupedParallel/test1/A=2
=== RUN   TestGroupedParallel/test1/B=1
=== PAUSE TestGroupedParallel/test1/B=1
=== CONT  TestGroupedParallel/test1/A=1
=== CONT  TestGroupedParallel/test1/B=1
=== CONT  TestGroupedParallel/test1/A=2
--- PASS: TestGroupedParallel (2.00s)
    --- PASS: TestGroupedParallel/test1 (0.00s)
        --- PASS: TestGroupedParallel/test1/B=1 (0.00s)
            testing_test.go:149: Len=2: 2019-12-10 19:57:05.678677 +0900 JST m=+0.000551289
        --- PASS: TestGroupedParallel/test1/A=2 (0.00s)
            testing_test.go:141: Len=2: 2019-12-10 19:57:05.678767 +0900 JST m=+0.000641739
        --- PASS: TestGroupedParallel/test1/A=1 (2.00s)
            testing_test.go:133: Len=2: 2019-12-10 19:57:07.681258 +0900 JST m=+2.003074682
    testing_test.go:153: finished
PASS
ok  	github.com/taisa831/sandbox-go/testing	2.009s
```

### `-run`オプションでテスト対象を絞る

`-run`オプションを指定することでテストファイル内のテスト対象を絞ることができます。

```sh 
# 全テスト対象
go test -run ''

# Fooにマッチするテストが対象
go test -run Foo

# FooにマッチかつサブテストA=にマッチするテストが対象
go test -run Foo/A=

# サブテストがA=1にマッチするテストが対象
go test -run /A=1
```

下記を実行すると`Foo/A=`にマッチするテストだけ実行されてるのが分かります。

```sh:実行
go test -v -run Foo/A=
=== RUN   TestFoo
=== RUN   TestFoo/A=1
=== RUN   TestFoo/A=2
--- PASS: TestFoo (0.00s)
    --- PASS: TestFoo/A=1 (0.00s)
    --- PASS: TestFoo/A=2 (0.00s)
PASS
ok  	github.com/taisa831/sandbox-go/testing	0.005s
```

## 共通処理のエラー箇所を分かりやすく出力する

ちょっとしたことですが、テストで共通処理を呼び出している時、どのテストでエラーが出たかは共通処理のコード情報しか出力されないので通常だと分かりません。そういう時は`helper()`を使うと呼び出し元のテスト情報を出力してくれます。

必ずエラーとなる`PreTest`関数を複数のテスト関数で呼び出して実行して確認してみます。また,`T`と`B`は`testing`の`TB`のインターフェースを実装（正確には`common`が実装してそれを両方とも持っている）しているので`*testing.T`も`*testing.B`も渡すことができます。

```go
func PreTest(tb testing.TB) {
	got := math.Abs(-1)
	if got != -1 {
		// t.Helper()
		tb.Errorf("Abs(-1) = %f; want 1", got)
	}
}
```

通常だと`PreTest`のエラー箇所である行情報しかでませんが、`t.Helper()`のコメントアウトを外してもう一回実行してみます。

```sh:実行
go test
--- FAIL: TestAbs (0.00s)
    testing_test.go:155: Abs(-1) = 1.000000; want 1
--- FAIL: TestFoo (0.00s)
    testing_test.go:155: Abs(-1) = 1.000000; want 1
    testing_test.go:97: finished
```

呼び出し元のテスト側の行情報がでるようになりました。

```sh:実行
 go test
--- FAIL: TestAbs (0.00s)
    testing_test.go:12: Abs(-1) = 1.000000; want 1
--- FAIL: TestFoo (0.00s)
    testing_test.go:76: Abs(-1) = 1.000000; want 1
    testing_test.go:97: finished
FAIL
exit status 1
FAIL	github.com/taisa831/sandbox-go/testing	2.009s
```

## 前処理/後処理をする

`*testing.M`を利用すると、対象のテストに対して「前処理」や「後処理」を書くことができます。テスト対象ファイルに下記のように記述することで実行が可能です。また、上記の`--run`オプションで対象テストを絞っても「前処理」と」後処理」は実行されます。

```go 
func TestMain(m *testing.M) {
	println("前処理")

	m.Run()

	println("後処理")
}
```

テストの最初と最後に「前処理」と「後処理」がプリントされました。

```sh:実行
go test -v
前処理
=== RUN   TestAbs
--- PASS: TestAbs (0.00s)
=== RUN   TestAbs2
--- PASS: TestAbs2 (0.00s)
=== RUN   TestTimeConsuming
--- PASS: TestTimeConsuming (0.00s)
=== RUN   TestFoo
=== RUN   TestFoo/A=1
=== RUN   TestFoo/A=2
=== RUN   TestFoo/B=1
--- PASS: TestFoo (0.00s)
    --- PASS: TestFoo/A=1 (0.00s)
    --- PASS: TestFoo/A=2 (0.00s)
    --- PASS: TestFoo/B=1 (0.00s)
=== RUN   TestGroupedParallel
=== RUN   TestGroupedParallel/test1
=== RUN   TestGroupedParallel/test1/A=1
=== PAUSE TestGroupedParallel/test1/A=1
=== RUN   TestGroupedParallel/test1/A=2
=== PAUSE TestGroupedParallel/test1/A=2
=== RUN   TestGroupedParallel/test1/B=1
=== PAUSE TestGroupedParallel/test1/B=1
=== CONT  TestGroupedParallel/test1/A=1
=== CONT  TestGroupedParallel/test1/B=1
=== CONT  TestGroupedParallel/test1/A=2
--- PASS: TestGroupedParallel (2.00s)
    --- PASS: TestGroupedParallel/test1 (0.00s)
        --- PASS: TestGroupedParallel/test1/B=1 (0.00s)
            testing_test.go:160: Len=2: 2019-12-10 21:48:38.890123 +0900 JST m=+0.000768137
        --- PASS: TestGroupedParallel/test1/A=2 (0.00s)
            testing_test.go:152: Len=2: 2019-12-10 21:48:38.890183 +0900 JST m=+0.000827182
        --- PASS: TestGroupedParallel/test1/A=1 (2.00s)
            testing_test.go:144: Len=2: 2019-12-10 21:48:40.89206 +0900 JST m=+2.002648644
    testing_test.go:164: finished
=== RUN   ExampleHello
--- PASS: ExampleHello (0.00s)
=== RUN   ExampleSalutations
--- PASS: ExampleSalutations (0.00s)
=== RUN   ExamplePerm
--- PASS: ExamplePerm (0.00s)
PASS
後処理
ok  	github.com/taisa831/sandbox-go/testing	(cached)
```

## その他

`testing`パッケージには他にも`io`テストをしやすくする為の`iotest`パッケージや、ブラックボックステスト用である`quick`パッケージ（ただし凍結されている模様）があります。

## おわりに

`Go`は標準で[モックライブラリ](https://github.com/golang/mock)も用意しているので組み合わせれば標準でほとんどのテストができます。また`httptest`もあるので`e2e`テストもできます。これらをうまく使いこなして楽しい開発ライフを送りたいと思います。

余談ですが、本記事を書くにあたり`GoDoc`をいろいろみていたら気になる箇所があったので`Go`本体にコミット&レビュー依頼してみたところ、何度かやりとりした後、無事取り込んでくれました。

`GitHub`ではなく`Gerrit`を使っているので最初のセットアップは少し面倒ですが、一度セットアップすると以降は簡単にレビュー依頼をすることができます。下記の本家記事と日本語の記事がとても分かりやすいので是非参考にしてみてください。

- [Contribution Guide](https://golang.org/doc/contribute.html)
- [Go にコントリビュートするまでの手順](https://syfm.hatenablog.com/entry/2017/07/05/020535)

## 参考

- [https://github.com/golang/go/tree/master/src/testing](https://github.com/golang/go/tree/master/src/testing)

明日の[テックタッチアドベントカレンダー](https://qiita.com/advent-calendar/2019/techtouch)の担当は [@takakobem](https://qiita.com/takakobem) です！