https://zenn.dev/mizchi/articles/my-test-policy
(社内用ドキュメントの公開版)
前提として、ユニットテストを導入するコストを、限界まで低くすることを目指す。テストが根付いていない言語環境や文化では、放っておくとテストが書かれないまま実装が進行し、結果としてテスト不可能な巨大な雪だるまが完成する。こうなるとメンテコストが高いE2Eを大量に書かないといけなくなり、テストの実行時間が膨れ上がっていく。
そうなる前に、ユニットテストを書きやすい環境を維持し、ユニットテストとして問題を切り分けられるような環境を維持する。とにかく書きやすさを重視し、一つのユニットテストを書くオーバーヘッドを限界まで下げる。
自分の経験的には、ユニットとテストの最初の一つを書いたらあとは自然とその周辺で増えていく。サンプルがあったら人はコピペする。逆にいうと最初の一つを書かない限り一切書かれない。まず一つ用意するのが大事。
一つ、といっても結局実装する対象によってパターンがあり、パターンごとに雛形を用意する必要がある。
自分のやるフロントエンド領域だと、こういうパターンが多い。
@sinonjs/fake-timers
や vi.useFakeTimers()
)もちろん作る対象によるので、都度作る。
ユニットテストと比較して E2E が重要ではない、というわけではないが、プログラマにとってはユニットテストの方が「安く、速く、うまい」。
E2E テストはブラックボックステストであり、実行において内部実装を知る必要はなく、開発者以外に向いた最終的な振る舞いを表現する。対して、ユニットテストはプログラマがそのプロジェクトを進行させるための「心理的安全性を担保する」ために必要なものと考えている。内部仕様を表現されていれば、機能変更やリファクタを安全に行うことが可能になる。
ユニットテストは E2E テストと独立しているが、間接的に E2E を通すために下支えとなる。責務を分割できない実装すると、自然に E2E が増えてしまう。つまり、理論的にはモジュールごとに正しい責務を分割できていれば、本来の目的である E2E テストは最小限で済むはずである。
その際の指標としてテストカバレッジがあるが、対象によるが 80~90% あたりにカバレッジをあげていくペイラインがあると思う。それを下回らないようにする。ブラウザ用のコードでも 60%切ってると危険。