外部テストパッケージの利用ケース #golang

[go list](http://golang-jp.org/cmd/go/#hdr-Go________)の、-fフラグで指定できるstruct fieldに

```
XTestGoFiles []string // パッケージ外の_test.goファイル
XTestImports []string // XTestGoFilesからのインポート
```
というものがあるのに気付いて、「これなんだろ？」と思って調べました。

テストコードのパッケージを`xxx_test`という様にサフィックス`_test`くっつけておくと外部テストパッケージ（external test package）というものになるらしい。

## 例

```
src
└── hoge
    ├── hoge.go
    └── hoge_test.go
```

hoge.go:

```go
package hoge

// Hoge returns hoge!!
func Hoge() string {
	return "hoge!!"
}

```

hoge_test.go:

```go
package hoge_test

import (
	"hoge"
	"testing"
)

func TestHoge(t *testing.T) {
	if hoge.Hoge() != "hoge!!" {
		t.Fatalf("expected:hoge!! but was:%v", hoge.Hoge())
	}
}
```

通常パッケージディレクトリ内に複数パッケージを宣言することはできないですが、外部テストパッケージ`{package name}_test`は例外で、そこに書かれたテストはhogeパッケージとは別のパッケージ扱いになるとのこと。

↑の例でも、hoge_testはhogeパッケージと同じディレクトリにありながら、hogeパッケージの関数を呼ぶときはhogeをimportしてパッケージプレフィクス付きで関数呼ぶ必要があります。

検索してもあまり情報ひっかからないのでマイナーな機能なのかな？と思っていたのですが、標準パッケージのコード見てるとめっちゃ使われてました。

数えてみました↓↓
通常パッケージの`_test.go`ファイル: 317
外部テストパッケージの`_test.go`ファイル: 234

## どういうときに使用する？

### Exampleテスト

FYI: https://golang.org/pkg/testing/#hdr-Examples

テストコードでExampleXxxという関数を書いておくと、標準出力をassertionするテストと、godocでのExample表示を同時に行ってくれます。
Exampleテストを記述するときには基本的に外部テストパッケージを使用します。

例:

```go
package hoge_test

import (
	"fmt"
	"hoge"
	"testing"
)

func ExampleHoge() {
	fmt.Println(hoge.Hoge())

	// Output:
	// hoge!!
}
```

godoc:

<img width="250" alt="スクリーンショット 2016-12-29 8.39.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/e2c6c27d-c9b3-fdd5-bdcb-3725ae772ffc.png">

外部テストパッケージでない通常のパッケージでも記述することは出来ますが、そうするとテスト対象と同じパッケージになってしまうので、godocで表示されるExampleもパッケージプレフィクスなしのコードになってしまいます↓↓

<img width="362" alt="スクリーンショット 2016-12-29 9.17.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/a2e1191a-182f-d9cd-ffe7-a3d59663e8ed.png">

これだと利用者がサンプルをそのまま実行できなくなります。外部テストパッケージを利用することでユーザーが外部のパッケージから利用する場合のコードをExampleに出力することができる様になります。

あと、余談ですが、godocの`-play`オプションつけた場合に、自前パッケージのExampleにもplaygroundが表示されます（外部テストパッケージを使用しないと表示されません）。

<img width="250" alt="スクリーンショット 2016-12-29 8.59.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/31437/79765f86-77ad-2540-1b5b-42b268e8c0b7.png">

でもRunするとエラーになっちゃいました・・・(´･ω･`)
これ実行出来ている人いたら教えてくださいm(_ _)m

### 他のパッケージから使用されるケースのテスト

これは必須ではないのですが、標準ライブラリの外部テストパッケージの使われ方を見ていて自分が感じたことです。

たとえば自分のパッケージでencoding/jsonのMarshaller/Unmarshallerインターフェースを実装している場合など、外部のパッケージ経由で呼び出されるケースのテストで使用します。

hoge.go:

```go
type Fuga struct {
	Value int
}

func (f Fuga) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf(`{"value":%d}`, f.Value)), nil
}
```

hoge_test.go:

```go
func TestFugaMarshal(t *testing.T) {
	fuga := &hoge.Fuga{999}
	jsn, err := json.Marshal(fuga)
	if err != nil {
		t.Fatal(err.Error())
	}
	if string(jsn) != `{"value":999}` {
		t.Fatalf(`expected: {"value":999}, but was:%s`, string(jsn))
	}
}
```

外部テストパッケージを使用することで、hogeパッケージがjson/encodingパッケージに依存しなくなります。

↑の例ではもともと依存関係がありませんでしたが、たとえばhogeパッケージに依存するパッケージpiyoがあったとして、piyoパッケージ経由でhogeが呼び出されるテストも記述することが出来ます。
通常パッケージのテストだと循環依存になって実行することが出来ません。

## 最後に

外部テストパッケージの利用方針に関して、公式ドキュメントの類があまり見当たりませんでした。
どなたか情報ありましたら教えてくださいm(_ _)m

あと、逆に通常テストパッケージを利用する意義が自分の中で曖昧になりました。。
テストは全部外部テストパッケージでいいのでは・・
unexportedな関数や変数をテストしたい場合・・・などかな？