cweill/gotestsでTable Driven Testsをらくらく実行

# はじめに
Table Driven Tests（テーブルドリブンテスト。以下、TDT）とは、入力値と期待値などをもったテストケースを用意し、順次実行していくテスト手法です。
ここでいうTableとはエクセルのようなスプレッドシート、すなわち表のことを指し、テストケースを網羅した表を用意するようにテストコードを用意していきます。
公式でも使われています。
https://github.com/golang/go/wiki/TableDrivenTests

# TDTの例
例として、挨拶メッセージを返すメソッドをテストしてみましょう。   
引数の時刻によって「おはよう」「こんにちは」「こんばんは」の3種類のメッセージのうちどれか1種類が返されます。
条件と期待結果は以下のとおりです。

| Input       	| Output      	|
|-------------	|------------	|
| 05:00-11:59 	| おはよう   	|
| 12:00-17:59 	| こんにちは 	|
| 18:00-04:59 	| こんばんは 	|

メソッドは以下のとおり。

```go
// greeter.go

package main

import "time"

func Greet(time time.Time) string {
	hour := time.Hour()
	switch {
	case 5 <= hour && hour <= 11:
		return "おはよう"
	case 12 <= hour && hour <= 17:
		return "こんにちは"
	case (18 <= hour && hour <= 23) || (0 <= hour && hour <= 4):
		return "こんばんは"
	}
	panic("Unknown Hour")
}
```

## ボイラープレートの生成をcweill/gotestsに任せる
[公式例](https://github.com/golang/go/wiki/TableDrivenTests)のようにテストを書いていこう！としても、なかなか面倒です。
そこでcweill/gotestsを活用していきます。   
gotestsはメソッドシグネチャを読み取り、テスト用のボイラープレートを自動生成してくれます（大感謝）。      


https://github.com/cweill/gotests



```
// 2019/10/08 最新版
go get -u github.com/cweill/gotests@v1.5.3

// greeter.goのテストコードを生成
gotests -w -all greeter.go
```

## テストケースを追加していく
以下のような`greeter_test.go`が生成されたはずです。
nameがテスト名、argsがGreetの引数、wantが期待結果を指します。

```go
// greeter_test.go

package main

import (
	"testing"
	"time"
)

func TestGreet(t *testing.T) {
	type args struct {
		time time.Time
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Greet(tt.args.time); got != tt.want {
				t.Errorf("Greet() = %v, want %v", got, tt.want)
			}
		})
	}
}
```

実際に`// TODO: Add test cases.`の箇所にケースを追加していきましょう。   
境界値を意識すると、テストはこんな感じになるかと思います（便宜的に3ケースだけ掲載）。

| Name                     	| Input 	| Output      	|
|--------------------------	|-------	|------------	|
| 05:00 expects おはよう   	| 05:00 	| おはよう   	|
| 11:59 expects おはよう   	| 11:59 	| おはよう   	|
| 12:00 expects こんにちは 	| 12:00 	| こんにちは 	|


コードで網羅すると、テストメソッドは以下のようになります。

```go
package main

import (
	"testing"
	"time"
)

func TestGreet(t *testing.T) {
	type args struct {
		time time.Time
	}

	tests := []struct {
		name string
		args args
		want string
	}{
		// おはよう
		{
			name: "05:00 expects おはよう",
			args: args{
				time: time.Date(2019, 1, 1, 5, 0, 0, 0, time.Local),
			},
			want: "おはよう",
		},
		{
			name: "11:59 expects おはよう",
			args: args{
				time: time.Date(2019, 1, 1, 11, 59, 59, 59, time.Local),
			},
			want: "おはよう",
		},
		// こんにちは
		{
			name: "12:00 expects こんにちは",
			args: args{
				time: time.Date(2019, 1, 1, 12, 0, 0, 0, time.Local),
			},
			want: "こんにちは",
		},
		{
			name: "17:59 expects こんにちは",
			args: args{
				time: time.Date(2019, 1, 1, 17, 59, 59, 59, time.Local),
			},
			want: "こんにちは",
		},
		// こんばんは
		{
			name: "18:00 expects こんばんは",
			args: args{
				time: time.Date(2019, 1, 1, 18, 0, 0, 0, time.Local),
			},
			want: "こんばんは",
		},
		{
			name: "23:59 expects こんばんは",
			args: args{
				time: time.Date(2019, 1, 1, 23, 59, 59, 59, time.Local),
			},
			want: "こんばんは",
		},
		{
			name: "00:00 expects こんばんは",
			args: args{
				time: time.Date(2019, 1, 1, 0, 0, 0, 0, time.Local),
			},
			want: "こんばんは",
		},
		{
			name: "04:59 expects こんばんは",
			args: args{
				time: time.Date(2019, 1, 1, 4, 59, 59, 59, time.Local),
			},
			want: "こんばんは",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Greet(tt.args.time); got != tt.want {
				t.Errorf("Greet() = %v, want %v", got, tt.want)
			}
		})
	}
}
```

## Run
書き終わったら、あとはテストを走らせるだけ。   
input/outputが網羅されて、わかりやすいテストになりました。

```
Running tool: /usr/local/go/bin/go test -timeout 30s github.com/mshrwtnb/sandbox -run ^(TestGreet)$ -v

=== RUN   TestGreet
=== RUN   TestGreet/05:00_expects_おはよう
=== RUN   TestGreet/11:59_expects_おはよう
=== RUN   TestGreet/12:00_expects_こんにちは
=== RUN   TestGreet/17:59_expects_こんにちは
=== RUN   TestGreet/18:00_expects_こんばんは
=== RUN   TestGreet/23:59_expects_こんばんは
=== RUN   TestGreet/00:00_expects_こんばんは
=== RUN   TestGreet/04:59_expects_こんばんは
--- PASS: TestGreet (0.00s)
    --- PASS: TestGreet/05:00_expects_おはよう (0.00s)
    --- PASS: TestGreet/11:59_expects_おはよう (0.00s)
    --- PASS: TestGreet/12:00_expects_こんにちは (0.00s)
    --- PASS: TestGreet/17:59_expects_こんにちは (0.00s)
    --- PASS: TestGreet/18:00_expects_こんばんは (0.00s)
    --- PASS: TestGreet/23:59_expects_こんばんは (0.00s)
    --- PASS: TestGreet/00:00_expects_こんばんは (0.00s)
    --- PASS: TestGreet/04:59_expects_こんばんは (0.00s)
PASS
ok  	github.com/mshrwtnb/sandbox	1.309s
Success: Tests passed.
```

以上