どんな本か
単体テストの価値を最大限引き出す「良い」テストを書くための原則と実践方法のパターンを紹介する本。
構成
大きく4つのパートに分かれている。
- 単体テストの概要・一般的に広く知られている単体テストの原則の紹介 (第1〜3章)
- 良い単体テストを構成するものとは何か&どうすれば既存のテストをより価値のあるものにすることができるのかの解説 (第4〜7章)
- 結合テストについて (第8〜10章)
- 単体テストでよくあるアンチパターンの紹介 (第11章)
今回は第2部のメモ
第2部 単体テストとその価値
第4章 良い単体テストを構成する4本の柱
良い単体テストを構成する4本の柱
- 退行 (regression) に対する保護
- リファクタリングへの耐性
- 迅速なフィードバック
- 保守のしやすさ
退行 (regression) に対する保護とリファクタリング
退行 (regression) に対する保護とは
退行 (regression) : コードの変更に伴って、既存の機能が正しく動かなくなること
退行 (regression) に対する保護 : テストをすることで退行を検出できる性質
テスト時に実行されるプロダクション・コードの量が多いほど、多くの退行を検出できる
リファクタリングへの耐性とは
リファクタリングへの耐性 : コードをリファクタリングを可能にする性質
偽陽性 (false positive) : テスト対象のコードに問題がないにもかかわらず、テストが失敗すること (嘘の警告)
偽陰性 (false negative) : テスト対象のコードに問題があるにもかかわらず、テストが成功すること (警告されないバグ)
ここでの positive
は、あることを検証した際に、なんらかの反応が検出されること
を指します。
つまり、テストを実施した際に失敗した
という結果が検出された場合、そのテストは positive (陽性)
です。
逆に、negative
は、あることを検証した際に、反応が検出されないこと
を指します。
嘘の警告が出るテストは、プロダクション・コードの正しい振る舞いを検証していないため、
対象のコードのリファクタリングを不可能にする。
偽陽性は、テスト・スイート&開発全体にどんな影響を与えるのか
- 開発者のプロダクション・コードの問題を解決する意思と能力を弱める
- 開発者が嘘の警告に見慣れてしまい、注意を払わなくなる
- テストを信頼できるセーフティ・ネットとして見ることができなくなる
偽陽性はなぜ発生するのか
- 偽陽性は、テスト対象のコードの内部と結びつくことで発生する
退行に対する保護とリファクタリングへの耐性はテストの正確性に関わる
- テストをすることでどのくらいバグを検出できるのか
- 検出できていないバグが少ないこと
- 偽陰性によって示される
- 検出できていないバグが少ないこと
- テストをすることでバグがないことをどのくらい示せるのか
- 嘘の警告が少ないこと
- 偽陽性によって示される
- 嘘の警告が少ないこと
迅速なフィードバックと保守のしやすさ
迅速なフィードバック : テストの検証結果をすぐに受け取ることができる性質
迅速なフィードバックがあると何がいいか
- テストの頻度が増える
- 実施するテストの数が増える
- 用意できるテスト・ケースの数が増える
- コードの改善速度が速くなる
保守のしやすさ
- テスト・コードの保守性が高いかどうか
- テストの際に、プロセス外依存 (データベース、外部サービスなど) が常に正しく機能するようになっているかどうか
保守のしやすさがあると何がいいか
- テスト・ケースを理解しやすくなる
- プロセス外依存が機能するよう、適切な処置がされている場合、されていない場合に比べて、迅速なフィードバックを受け取ることができる
理想的なテストの探求
上の4つの性質をテストに常に備えることは不可能。
実施するテストの目的を理解し、優先度を設定することが重要
ソフトウェア・テストにおけるよく知られた概念
テスト・ピラミッド
第5章 モックの利用とテストの壊れやすさ
モックとスタブの違い
モック
テスト対象からその依存に向かって行われる、外部に向かうコミュニケーション (出力) を模倣する
コマンド・クエリ分離原則でいうところのコマンドにあたる動作を模倣したオブジェクト
- メール送信
- ファイルへの書き込み
スタブ
依存からテスト対象に向かって行われる、内部に向かうコミュニケーション (入力) を模倣する
コマンド・クエリ原則でいうところのクエリにあたる動作を模倣したオブジェクト
- メール受信
- ファイルの読み込み
コマンドクエリ分離原則について(https://bliki-ja.github.io/CommandQuerySeparation/)
基本的な考えは、オブジェクトのメソッドを明確に2つのカテゴリに分類するというものである。
- 問い合わせ:結果を返し、システムの状態を変更しない(副作用がない)
- コマンド:システムの状態を変更し、値を返さない