https://future-architect.github.io/articles/20200601/

TIG の辻です。今回は春の入門祭りということで Go のテストに入門してみよう!という記事です。

書いた背景ですが Go の標準ライブラリのコードリーディング会で testing パッケージにチャレンジしてみましたが、難しすぎてわからん。そもそも Go のテストって何ができるんだっけ?という話になり、基本的な内容をなるべく具体例をまじえながらまとめました。

ざっとどんなことができるんだろう、という index になれば幸いです。

Go に組み込まれているテストの仕組みの中に、ベンチマークに関するテストと Example テストというサンプルコード用のテストも含まれているのですが、この 2 つは対象外にします。基礎的と思われる内容から順に並べてみました。

Goのテストは go test コマンドを用いてテストを実施します。テストを実施する関数の命名は以下のような形式でなければなりません。

TestXxxTestxxx ではダメです。Test_xxx という関数名であれば問題ありません。

テストファイルは xxxx_test.go といった命名である必要があります。このファイルはビルド時には除かれます。簡単なテストを試してみます。

main_test.go

上記のテストは TableDrivenTest とサブテストを組み合わせています。どちらも現場でよく使われます。サブテストを用いると各テストごとに結果がわかるようになります。 TableDrivenTest はさまざまな Input/Output パターンを網羅するのに便利です。上記のテストをシンプルに書き直すと以下のようになります。

Go はテストのアサーションを提供していません。理由は公式のFAQで紹介されています。先程の TestAddc 関数のように、テストが失敗したことを開発者が自ら実装する必要があります。失敗したことを示すには T.Error (T.Errorf)T.Fatal (T.Fatalf) を用いることができます。

T.Fatal を用いると T.Fatal が実行された以降のテストは呼び出されずに終了します。テストが失敗したことを示すには T.Error を使い、テストの初期化など、処理が失敗するとその後のテストが無意味になる場合は T.Fatal を用いると良いでしょう。以下のように t.Fatalf を用いた場合は、その後のテストの処理 t.Log("after add() ...") が呼び出されていないことが分かります。deferT.Cleanup といった後処理は呼び出されます。

なお t.Fatalf と似たような関数名でログ出力してアプリケーションを終了する log パッケージの Fatalf という関数があります。log.Fatalf のGo Docにもあるように log.Fatalfdefer といった後処理を呼び出さずに即座に os.Exit(1) でアプリケーションが終了します。t.Fatalflog.Fatalf を混乱しないように注意しましょう。

時間がかかるテストなど、自動テストなどではテストをスキップしたい場合があるかもしれません。次のようなある条件の場合は処理にめちゃくちゃ時間がかかる例を考えてみます。

このテストをスキップしたいとします。その場合は func (c *T) Skip(args ...interface{}) というメソッドを用いることでスキップできます。

テストコードに以下を追加します。

テストがスキップされていることが分かります。さらっと testing.Short() という関数も用いましたが Short()testing パッケージに含まれている関数で、-short フラグがセットされていると true になります。そのためテストを実施するときに -short というフラグを付与したときだけテストがスキップされる、そうでないときはスキップされずテストが実施される、というように使い分けることができます。

標準パッケージでもテストのスキップが実装されているのを色々見ることができます。以下は io/ioutil/ioutil_test.go からの抜粋です。特定の条件を満たす場合にテストをスキップするように実装されています。

io/ioutil/ioutil_test.go