The Go Blog

Goにおけるテスト可能な例

Andrew Gerrand
2015年5月7日

はじめに

Godocのは、パッケージのドキュメントとして表示され、テストとして実行することで検証されるGoコードの断片です。これらは、ユーザーがパッケージのgodocウェブページを訪れ、関連する「実行」ボタンをクリックすることでも実行できます。

パッケージの実行可能なドキュメントを持つことで、APIの変更によって情報が古くなることがないことが保証されます。

標準ライブラリには、そのような例が多数含まれています(例えば、stringsパッケージを参照)。

この記事では、独自の例関数を記述する方法を説明します。

例はテストです

例は、パッケージのテストスイートの一部としてコンパイルされ(そしてオプションで実行されます)。

一般的なテストと同様に、例はパッケージの_test.goファイルに存在する関数です。ただし、通常のテスト関数とは異なり、例関数は引数を受け取らず、TestではなくExampleという単語で始まります。

reverseパッケージは、Goの例のリポジトリの一部です。ここに、そのString関数を示す例があります

package reverse_test

import (
    "fmt"

    "golang.org/x/example/hello/reverse"
)

func ExampleString() {
    fmt.Println(reverse.String("hello"))
    // Output: olleh
}

このコードは、reverseディレクトリのexample_test.goに置かれるかもしれません。

Goパッケージドキュメントサーバーpkg.go.devは、この例をString関数のドキュメントと一緒に提示します

パッケージのテストスイートを実行すると、追加の手配なしで例関数が実行されることがわかります

$ go test -v
=== RUN   TestString
--- PASS: TestString (0.00s)
=== RUN   ExampleString
--- PASS: ExampleString (0.00s)
PASS
ok      golang.org/x/example/hello/reverse  0.209s

出力コメント

ExampleString関数が「合格する」とはどういう意味でしょうか?

例を実行する際、テストフレームワークは標準出力に書き込まれたデータをキャプチャし、その出力を例の「Output:」コメントと比較します。テストの出力がその出力コメントと一致すれば、テストは合格です。

失敗する例を見るには、出力コメントのテキストを明らかに間違ったものに変更できます

func ExampleString() {
    fmt.Println(reverse.String("hello"))
    // Output: golly
}

そして、もう一度テストを実行します

$ go test
--- FAIL: ExampleString (0.00s)
got:
olleh
want:
golly
FAIL

出力コメントを完全に削除すると

func ExampleString() {
    fmt.Println(reverse.String("hello"))
}

例関数はコンパイルされますが、実行されません

$ go test -v
=== RUN   TestString
--- PASS: TestString (0.00s)
PASS
ok      golang.org/x/example/hello/reverse  0.110s

出力コメントのない例は、ネットワークにアクセスするような単体テストとして実行できないコードを示すのに役立ちますが、例が少なくともコンパイルされることを保証します。

例関数の名前

Godocは、例関数をパッケージレベルの識別子と関連付けるための命名規則を使用します。

func ExampleFoo()     // documents the Foo function or type
func ExampleBar_Qux() // documents the Qux method of type Bar
func Example()        // documents the package as a whole

この規則に従って、godocはExampleStringの例をString関数のドキュメントと一緒に表示します。

特定の識別子に対して複数の例を提供するには、アンダースコアの後に小文字が続く接尾辞を使用します。これらの各例はString関数を文書化します

func ExampleString()
func ExampleString_second()
func ExampleString_third()

より大きな例

良い例を書くには、関数だけでは不十分な場合があります。

例えば、sortパッケージを示すには、sort.Interfaceの実装を示す必要があります。メソッドは関数本体内で宣言できないため、例には例関数に加えて何らかのコンテキストを含める必要があります。

これを実現するには、「ファイル全体例」を使用できます。ファイル全体例とは、_test.goで終わり、厳密に1つの例関数、テストまたはベンチマーク関数なし、そして少なくとも1つの他のパッケージレベルの宣言を含むファイルです。そのような例を表示する場合、godocはファイル全体を表示します。

ここに、sortパッケージからのファイル全体例があります

package sort_test

import (
    "fmt"
    "sort"
)

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s: %d", p.Name, p.Age)
}

// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }

func Example() {
    people := []Person{
        {"Bob", 31},
        {"John", 42},
        {"Michael", 17},
        {"Jenny", 26},
    }

    fmt.Println(people)
    sort.Sort(ByAge(people))
    fmt.Println(people)

    // Output:
    // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
    // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
}

パッケージには複数のファイル全体例を含めることができます。1ファイルにつき1つの例です。実際にこれを確認するには、sortパッケージのソースコードをご覧ください。

まとめ

Godocの例は、ドキュメントとしてコードを記述し、維持するのに最適な方法です。また、編集可能で、動作し、実行可能な例をユーザーに提供し、それを基に構築できます。ぜひご活用ください!

次の記事: GopherChina旅行記
前の記事: パッケージ名
ブログインデックス