Golangでキャッシュなしでテストを実行する

Golangでキャッシュなしでテストを実行する

2025年2月14日

image

Golangでテストを行うと、2回目以降はテスト速度が非常に速くなる。

1回目

ok      github.com/my/package/test    126.752s

2回目

ok      github.com/my/package/test    (cached)

1回目は2分以上かかったが、2回目は計測する暇もなく速くテストが終了してしまった。

実際には性能的に変わったわけではなく、コードが変更されていない場合、テスト結果をキャッシュを通じて再利用するためである。

統合テスト

まず、統合テストとは複数のコンポーネントを一つにまとめてテストすることを指す。

モッキングを主にするユニットテストとは異なり、実際のコンポーネントを主に扱うため、テスト速度が遅いのが特徴である。

ただし、APIサーバーではこのような統合テストが実際のユーザーの行動を最も実物に近くテストできるため、しばしば使用される。

統合テストではこのようなキャッシュ関連の部分を除外する必要があることがある。

統合テストでキャッシュなしでテストする理由

すべての統合テストでそうではない。実際冪等性を保証するテストであれば、キャッシュを使用しても問題ない。

もし外部サービスのようなものを使用せず、テストにもこのようなものが除外されているなら、キャッシュを使っても問題ない。(むしろそのような場合にはテスト時間を少しでも短縮するために使用すべきである)

しかし、外部サービスの使用が多く、テストが冪等性を保証しない場合(毎回結果が変わるなど)、そして外部サービスの変更によって修正が必要な事由が多い場合、 キャッシュされた結果をそのまま信じるより、そのつどテストを実行した方が良いだろう。

キャッシュなしでテストする

理由はさておき、キャッシュを使用しない方法は非常に簡単である。go test のフラグで -count 1 を使用すれば良い。

go test -count 1 -v ./...

このような方式ならキャッシュを使用せず、毎回テストを実行することができる。

なぜ -count 1 なのか?

-count 1 は実はキャッシュをしろ、するなというコマンドではない。ただテストを何回実行するかを指定するものである。

また公式文書によればデフォルト値も1なので、本来は省略しても同じ動作をするはずのオプションである。

-count n
    Run each test, benchmark, and fuzz seed n times (default 1).
    If -cpu is set, run n times for each GOMAXPROCS value.
    Examples are always run once. -count does not apply to
    fuzz tests matched by -fuzz.

ただし、このオプションはその動作が同じではない。

意図かどうかはわからないが、公式文書でも次のようにキャッシュを無効化する慣用的な方法として -count 1 を使用するよう指示している。

“The idiomatic way to disable test caching explicitly is to use -count=1.”

結びに

実際に方法論として -count 1 というオプションでキャッシュの有無を決定するのは、私の考えでは設計ミスと思われる。

一般的にはデフォルトオプションと同じ値を人々は入れる必要がないと考えるからである。

むしろバグと言ってもよいほどだが、なぜGoではこのような方法を維持しているのかわからない。むしろ -no-cache のようなフラグを設けてもっと明確にした方が良かったのではないか…?