Goでどのtesting frameworkを使ってテストを書くか、あるいはkubernetesで何が使われているか

Posted on

Motivation

もともと僕はGoの教えの通り、標準のtestingパッケージのみを使ってテストを書いていた。

当初は面倒くさいなと思っていたが今ではこのスタイルが気に入っているし、特に困ってもいないのだが、メジャーなパッケージくらいは抑えておいたほうが良いのではないかと思い、個人開発でも何らかのパッケージを導入してみようと思い立った。

メジャーどころ

  • stretchr/testify
    • 観測範囲内では一番メジャーなパッケージ
    • 用途別にいくつかのサブパッケージが存在していて、必要なものをimportして使用する
      • 一例:
      • github.com/stretchr/testify/assert
      • github.com/stretchr/testify/mock
    • ポピュラーな使い方はgithub.com/stretchr/testify/assertを使ったassertだと思う
    • 素のtestingパッケージのみだとif文で判定してt.Errorを書くようなパターンの代替としてassertを用いることで簡潔に書ける
  • onsi/ginkgo/
    • BDDに特化している
    • testifyよりもカバー範囲が広い
      • go testコマンドをラップしたginkgoコマンドが存在する
      • TestSuiteの概念が採用されており、Go標準のTest.*メソッドはginkgoのエントリポイントしか必要なく、後はginkgo内で提供されるメソッドを実行している
        • テスト実行を全てginkgo側で制御出来るのでsetup/teardownはもちろん、一時的にこのテストだけ実行したいといったことも簡単に出来る
      • テスト実行結果のレポートがやけに親切
    • 実際に書くテストはginkgoのDSLを書いている感覚に近い
    • testifyに比べ重厚感があるが、DescribeContextなどを用いてこのテストが何を行っているかは明確になりやすい

kubernetesの使用例

先人の知恵を参考にしようということでkubernetes/kubernetesを見てみた。

雑な結果は以下の通り:

$ rg 'onsi/ginkgo' | wc -l
     647
$ rg 'stretchr/testify' | wc -l
     357

実際にどの辺りのパッケージで使われているかをみると、testifyはユニットテストっぽいところ、ginkgoはE2Eテストっぽいところで多く使われている傾向が見えた。

ただし僕自身はkubernetesのパッケージ構成に詳しくないので的外れなことを書いている可能性は大いにある。

使い分け

kubernetesの例からも分かる通り、何かに絞るのではなく適材適所で使っていくのが良さそう。

  • testify
    • 1つのパッケージ内に閉じるようなユニットテスト
    • いわゆる普通の.*_test.goで使う
  • ginkgo
    • 複数のパッケージ、あるいは複数のmicroservices間を跨ぐようなE2Eテスト
    • 専用のe2eパッケージなどで使う

ginkgoのドキュメントにも書いてある通り、testifyginkgoでは同じtesting frameworkをいえどもレイヤが異なるので、それぞれで使い分けるのは理に適っているように思える。

あるいは単純にBDDで書きたいのでginkgoを採用する、でも全然良いと思う。

まとめ

(個人的に)メジャーどころのパッケージ2つを紹介し、使用事例と適用箇所について書いた。

もちろんこれら以外にもtesting frameworkは数多く存在しているし、kubernetesでもそれらを使っているかもしれないので、判断基準の一つとして少しでも参考になれば幸いである。