11章
ソフトウェアのテストを望む理由として同等に重要なものは、変化を可能とする能力を備えておくため、という理由である
より高速に反復できる企業こそが、変化する技術、市場の状況、顧客の好みに対し、より迅速に適応できる。
自動テストを書くことにより、開発サイクルの初期にこうした問題に向き合うことを強制される。
11.1 何故テストを書くのか
- テストスイート (test suite)
- 何百あるいは何千もの単純なテストをまとめたもの
Googleでは、テストは後からの付け足しであってはならないと定めている
11.1.3 書き、実行し、反応する
テストの自動化は、その最も純粋な形式では3つの活動から成る。
- テストを書くこと
- テストを実行すること
- テストの失敗に反応すること
テストのプロセスを真に効果的とするのは、テストの失敗にどう対処するかである。
テスト失敗の数分以内にその破綻したテストを修正することを優先するチームは、信頼性を高く保つとともに失敗の切り分けの速度を高速に保つことができ、ひいてはテストからより大きな価値を引き出せる。
11.1.4 コードをテストする利点
- デバッグの減少
- 変更への信頼の増大
- ドキュメンテーションの改善
- レビューの単純化
- 思慮に富む設計
- 高速で高品質なリリース
11.2 テストスイートを設計する
開発するテストをどんどん小さくしていく方向へとチームを導いた。そのようなテストはより速く、より安定し、大体の場合面倒が減っていた。
11.2.1 テスト規模
- Googleでは各テストをすべて規模で分類している
- 任意の機能向けにいつでも可能な限り最小のテストを書くようエンジニアに推奨している
- 小テスト
- 単一のプロセス内で実行される
- シングルスレッド内で実行されなければならないと指定している
- 中テスト
- 単一のマシン上で実行される
- 大テスト
- 任意の好きな場所で実行される
伝統的な「ユニット」または「インテグレーション」の区別は用いていない。テストスイートに望む最も重要な特性は、テスト範囲とは無関係に、速度と決定性だからである
- 決定性 (determinism)
- すべての事象は、既存の原因によって完全に決定されているという世界観で、コンピューターサイエンスでは決定性アルゴリズムというとき、そのアルゴリズムは特定の入力に対して常に同じ出力を行う。
11.2.1.4 全テスト規模に共通の属性
- テストは共有データベースに依存すべきではない
テスト自体にはテストがないため、テストはその正しさについての重要なチェックとして手作業でのレビューを要する。この事の必然的帰結として、テスト内で条件分岐やループのような制御フロー分を利用することは強く非推奨となっている。
- Javaテストはすべてカスタムセキュリティマネージャを使って実行されている
- ネットワーク接続の確立などの禁止事項を実行しようと試みると、すべて失敗させる
11.2.2 テスト範囲
- 約80%がビジネスロジックの大部分を検証する狭い範囲のユニットテスト
- 15%が2つ以上のコンポーネント間の相互作用を検証する中範囲のインテグレーションテスト
- 5%が全システムを検証するエンドツーエンド(E2E)テスト
を目指そうとしている
11.2.4 カバレッジについてのメモ
カバレッジ計測は小テストにとどめておくことを我々は推奨している
11.7 要約
* 自動テストは、ソフトウェアの変化を可能とするための基盤である
* テストがスケールするには、自動化されなければならない。
* 健全なテストカバレッジを維持するには、バランスのとれたテストスイートが必要である
* 「そんなに好きならそいつにテストつけときゃよかったのに」
* 組織内のテスト文化を変えるには時間がかかる
12章
- 感想
- 普段テストを書いていて直面する悩みへの答えとなるヒントが色々見つけられた
- テストケースを書く単位、命名
- 特にテスト対象、ユニットのとらえ方は考え直したほうが良さそう
- テストにロジックを入れない
- テストケースでありがちなMockの検証(verify)
- assertThatを使う意義
- 共通メソッドやオブジェクト書く時の観点(→DAMP)
12.2.3 相互作用ではなく、状態をテストせよ
- ステートテスト
- インタラクションテスト
- インタラクションテストはステートテストより脆い
インタラクションテストに問題がある場合、その問題の理由としてもっともありふれたものは、木琴ぐフレームワークへの過度の依存である。
我々は、本物のオブジェクトが高速で決定性である限りは、モックオブジェクトよりも本物のオブジェクトを使うことを好む傾向がある
12.3 明確なテストを書く
- 明確性
- その存在目的と失敗理由が、失敗の原因を究明するエンジニアから見てたちどころに明確となるテスト
12.3.1 テストは完全かつ簡潔にせよ
テストの明確性を向上する2つの属性
- 完全性
- 簡潔性
- 完全
- そのテストがどのようにその結果に到達するか理解するために読者が必要とする全情報をその本体部分が含んでいる場合
- 簡潔
- ほかの、紛らわしいか無関係な情報が含まれていない場合
テストの本体部分は、重要でない情報や紛らわしい情報は全く含まずに、テストを理解するのに必要な情報を全部含むべきであるということだ。
12.4 テストとコード共有:DRYでなくDUMP
- DAMP
- 説明的かつ意味が分かりやすい言い回し
- Descriptive And Meaningful Phrases
DAMPはDRYを置き換えるものではなく、補うものである。DRYなヘルパーメソッドと、テストのインフラストラクチャーは、テストを簡潔にし、繰り返されるステップでその詳細がテスト対象の特定の挙動に関係ないものを括り出すことにより、テストの明確性を高めるために依然として活用できる。
重要な点は、そのようなリファクタリングは、テストを説明的で意味が分かりやすいものにすることを重視して行われるべきであり、単に繰り返しを減らすという名目のみにおいて行われるべきではないということだ。
12.6 要約
* 変化しないテストを目指せ。
* 公開API経由でテストせよ。
* 相互作用でなく、状態をテストせよ。
* テストを完全かつ簡潔にせよ。
* メソッドではなく、挙動をテストせよ。
* 挙動に重点を置いてテストを構成せよ。
* テスト対象の挙動にちなんでテストに命名せよ。
* テストにロジックを入れるな。
* 明確な失敗メッセージを書け。
* テスト用コードを共有する場合、DRYよりDAMPに従え。
13章 テストダブル
- テストダブル (test double)
- テスト内で本物の実装の代役を務めることのできるオブジェクトまたは関数
- モッキング
13.1 テストダブルの、ソフトウェア開発への影響
- テスト可能性
- 応用性
- 忠実性
13.2 Googleでのテストダブル
我々が学んだ教訓に、モッキングフレームワークを使いすぎるのは危険である、というものがある
13.3.2 シーム
- テスト可能
- コードは、そのコード向けにユニットテストを書けるような形式で書かれている場合
- シーム
- テストダブルを利用できるようにすることで、コードをテスト可能とする方法
- Googleが使うDIフレームワーク
- Java
- Guice
- Dagger
- Java
13.3.3 モッキングフレームワーク
- Googleが使うモッキングフレームワーク
- Java
- Mockito
- C++
- Googletestのgooglemockコンポーネント
- Python
- unittest.mock
- Java
13.4 テストダブル利用のためのテクニック
13.4.1 フェイキング
- フェイク (fake)
- 本番環境には適していないが、本物の実装同様に振る舞うAPIの軽量な実装
13.4.2 スタビング
- スタビング
- 挙動を与えられなければそれ自体では何も挙動を持たないような関数に、挙動を与えるプロセス
13.4.3 インタラクションテスト
- インタラクションテスト
- 関数がどのように呼び出されるかを実際にその関数の実装を呼び出すことなしに検証する方法
- モッキング
- Mockitoでいうverify
13.5 本物の実装
テストについての我々の第一の選択は、テスト対象システムの依存関係に、本物の実装を利用することだ。
Googleでは、モッキングフレームワークを使いすぎると、本物の実装と動機が取れなくなりリファクタリングが難しくなったコードが繰り返し出てきて、テストが汚染される傾向が見られてきた。そのため、本物の実装を優先する流れが時間の経過とともに現れてきた。
13.5.2 いつ本物の実装を使うべきか決める方法
- 高速で、決定性で、持っている依存関係が単純である場合
13.10 要約
* テストダブルより本物の実装が優先されるべきである。
* テスト内で本物の実装が利用できないなら、フェイクが理想的な解法である場合が多い。
* スタビングを使いすぎると、不明確で脆いテストにつながる。
* インタラクションテストは、できるだけ避けるべきである。テスト対象システムの実装詳細を公開するため、脆いテストにつながるからだ。