A little bit of everything

元・情報系大学院生の備忘録

読書メモ:Googleのソフトウェアエンジニアリング(11章:テスト概観)

テストを書くメリット

  • 低コストでバグを見つけるため
    • 開発サイクルの後になればなるほど、指数関数的にバグ修正のコストが上がる
  • 変化を可能とする能力を備えておくため
    • 新規機能開発、リファクタリング、再設計など、どんな活動に対してもテストは素早く間違いを見つけられる。
  • システムの設計改善のため
    • 作ったコードの最初の利用者はテスト。システムはDBに密結合しすぎていないか、APIは要求されるユースケースに対応しているか、エッジケースに対処しているかなど、開発サイクルの初期段階でこうした問題と向き合うのに強制される。
    • テストしにくいコードは設計がよくない。モジュール化されていなかったり、依存関係が多かったりするせいで、テストが書きにくくなる。
  • ドキュメンテーションとしてのテスト
    • 特定の場合にコードが行うことを知りたければ、テストを見ればよい。
  • レビューの単純化
    • コードの正しさ、エッジケース、エラー条件などに対して徹底したテストが書かれており、それがコードレビューに含まれていれば、レビュアーはそのテストがパスするかを確認すればよい。レビュアーの労力が減る。


手作業でのテストは、とにかくスケールしない。テストに関する明確な答えは、自動化。

あらゆるテストに対して2つの次元がある。

規模と範囲。

  • テスト規模
    テストケースの実行に必要なリソース(メモリ、プロセス、時間、等)のこと。
  • テスト範囲
    検証している特定のコードパスのこと。

テスト規模

Googleではユニットテストやインテグレーションテストとは言わず、以下のように分けている。理由は、速度と決定性を最重要視しているため。

小テストでは、DB接続、ファイルI/O、ネットワークやディスクへのアクセスもNG。

Googleではさらに制約を厳しくして、シングルスレッド内で実行されなければならない、という指定をすることもあるらしい。

小テストのメリットは、とにかく非決定性を排除できること。
非決定性のせいでたまに失敗するテストのことを、flaky test(信頼不能テスト)と呼んでいる。


ちなみに、

  • 決定性:特定の入力に対して、常に同じ出力になること。
  • 非決定性:入力が同じでも、実行の度に出力が異なること。


信頼不能テストはコストが高い。

信頼不能テストで失敗する確率が0.1%でも、1日1万回テストが走れば、10回は失敗する。つまり、1日あたり10回の原因調査が必要になる。
信頼不能テストが増えることは、エンジニアが生産性を失うよりもまずいことが起きる。つまり、テストへの信頼の喪失が起こる。
テストへの信頼の喪失が起こると、エンジニアはテストの失敗に反応することをやめ、テストが提供する価値が失われる。信頼不能性が1%になるあたりで、テストは価値を失い始める。(Googleは0.15%くらいに留まっている)。

全テスト規模に共通の属性

すべてのテストは、密閉された状態となることを目指すべき。
つまり、テスト環境を組み立て、実行、解体するのに必要なすべての情報を含むべき。 テストは当該挙動を実行するのに必要な情報のみを含むべき。

テスト自体の正しさは手作業のレビューしかない。
つまり、テスト内で条件分岐やループのような制御フロー文を利用するのは強く非推奨。複雑なテストのフローは、それ自体がバグを含むリスクがある。

テスト範囲

テスト範囲は、あるテストでどれだけの量のコードが検証されるかを指している。

Googleは、このピラミッド型になるのを目指している。

↓これはアンチパターン

コードカバレッジ

コードカバレッジに関する問題は、すぐにそれ自体がゴールと化してしまうこと。
例えば「カバレッジ80%を目指す」というルールを課すと、エンジニアは80%を床ではなく天井だと考える。

「十分なテストがあるか」という問いにたった1つの数値だけで答えようとするのはたくさんの文脈を無視しており、有用とはなりえない。コードカバレッジはテストされていないコードについての何らかの知見を提供できるが、システムがどれだけ適切にテストされているかについて批判的に考えることの代用とはならない。