Goブログ

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

Andrew Gerrand
2015年5月7日

はじめに

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

パッケージの実行可能なドキュメントがあることで、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つの例です。実際にこれを確認するには、sortパッケージのソースコードをご覧ください。

結論

Godocの例は、ドキュメントとしてコードを記述および保守するための優れた方法です。また、編集可能で、動作し、実行可能な例をユーザーが構築できます。これらを使用してください!

次の記事: GopherChina訪問レポート
前の記事: パッケージ名
ブログインデックス