「単体テストの考え方/使い方」用語メモ
概要
「単体テストの考え方/使い方」で良かった文言を抜粋して、後からでも見返せるようにする。
1 章 なぜ、単体(unit)テストを行うのか?
優れたテストスイート
- テストすることが開発サイクルの中に組み込まれている
- コードベースの特に重要な部分のみがテスト対象となっている
- 最小限の保守コストで最大限の価値を生み出すようになっている
2 章 単体テストとは何か?
単体テストの定義
- 「単体(unit)」と呼ばれる少量のコードを検証すること
- 実行時間が短いこと
- 隔離された状態で実行されること
古典学派の観点における単体テストの意味
- 1 単位の振る舞い(a unit of behavior)を検証すること
- 実行時間が短いこと
- 他のテストケースから隔離された状態で実行されること
共有依存、プライベート依存、プロセス外依存
項目 | 内容 |
---|---|
共有依存 | テスト・ケース間で共有される依存のこと |
プライベート依存 | 共有されない依存のこと |
プロセス外依存 | アプリケーションを実行するプロセス外で稼働する依存のこと |
古典学派およびロンドン学派が考える単体テストの違い
隔離対象 | 単体の意味 | テスト・ダブルの置き換え対象 | |
---|---|---|---|
ロンドン学派 | 単体 | 1 つのクラス | 不変依存を除くすべての依存 |
古典学派 | テスト・ケース | 1 つのクラス、もしくは、同じ目的を達成するためのクラスの 1 グループ | 共有依存 |
協力者オブジェクト
次の性質を 1 つ以上持つ依存のこと
- 可変である(状態を変えることができる)こと
- まだメモリ上にはないデータの橋渡しをするもの(共有依存)であること
3 章 単体テストの構造的解析
4 章 良い単体テストを構成する 4 本の柱
良い単体テストを構成する 4 本の柱
- 退行(regression)に対する保護
- リファクタリングへの耐性
- 迅速なフィードバック
- 保守のしやすさ
「退行(regression)に対する保護」「リファクタリングへの耐性」「迅速なフィードバック」を全て最大にはできない。
「保守のしやすさ」は独立している。
「リファクタリングへの耐性」を犠牲にできないため、他の 2 つでバランスを取る。
テスト・ピラミッド
- 単体テスト -> 迅速なフィードバック
- 統合(integration)テスト -> 2 つの中間
- E2E(End-to-End)テスト -> 退行に対する保護
ホワイト・ボックス・テストとブラック・ボックス・テストの長所と短所
退行に対する保護 | リファクタリングへの耐性 | |
---|---|---|
ホワイト・ボックス・テスト | 優れている | 劣っている |
ブラック・ボックス・テスト | 劣っている | 優れている |
5 章 モックとスタブの違い
テスト・ダブルの種類
大きく分けてモックとスタブ
大別 | 小別 | 詳細 |
---|---|---|
モック | モック | テスト対象システムからその依存に向かって行われる、外部に向かうコミュニケーションを(出力)を模倣し、そして検証するのに使われる |
モック | スパイ | テスト対象システムに向かって行われる内部に向かうコミュニケーション(入力)を模倣するのに使われる |
スタブ | スタブ | モックと同じ役割を担うが、モックはモック・フレームワークを使うのに対し、スパイは開発者自身の手で実装される |
スタブ | ダミー | テスト対象システムのメソッド・シグネチャを満たすために使われる |
スタブ | フェイク | フェイクを使う目的はスタブの場合とほぼ同じである一方、通常、フェイクはまだ存在しない依存を置き換えるために作成される |
観察可能な振る舞い(observable behavior)
以下のどちらかでなければならない
- クライアントが目標を達成するために使う公開された操作
- クライアントが目標を達成するために使う公開された状態
第 6 章 単体テストの 3 つの手法
単体テストの 3 つの手法
- 出力値ベース・テスト(戻り値を確認するテスト)
- 状態ベース・テスト(状態を確認するテスト)
- コミュニケーション・ベース・テスト(オブジェクト間のやり取りを確認するテスト)
単体テストの 3 つの手法と 4 本の柱
出力値ベース・テスト | 状態ベース・テスト | コミュニケーション・ベース・テスト | |
---|---|---|---|
リファクタリングへの耐性を維持するのに必要なコスト | 低い | 普通 | 普通 |
保守のしやすさを維持するのに必要なコスト | 低い | 普通 | 高い |
※ 迅速なフィードバック、退行(regression)に対する保護
隠れた入力と出力の種類
- 副作用: メソッド・シグネチャには表現されていない出力のこと。
種類 | 入力/ 出力 | 意味 | 例 |
---|---|---|---|
副作用 | 隠れた出力 | メソッド・シグネチャには表現されていない出力のこと | オブジェクトの状態を変更することやディスク上のファイルを更新すること |
例外 | 隠れた出力 | メソッド・シグネチャで確立された契約を無視したプログラムの流れが作られること | |
内部もしくは外部の状態への参照 | 隠れた入力 | メソッド・シグネチャには定義されていない入力 | 静的なプロパティの参照、プライベートな可変のフィールドの参照 |
第 7 章 単体テストの価値を高めるリファクタリング
4 種類のプロダクションコード
以下の 2 つの観点から 4 つに分類できる
- コードの複雑さやドメインにおける重要性の観点
- 協力者オブジェクトの数の観点
コードの複雑さやドメインにおける重要性の観点\協力者オブジェクトの数 | 少ない | 多い |
---|---|---|
高い | ドメイン・モデル/アルゴリズム | 過度に複雑なコード |
低い | 取るに足らないコード | コントローラ |
コントローラにおける条件付きロジックの扱い
ビジネス・オペレーションを実施している最中に、プロセス外依存へのアクセスが要求される場合、以下の 3 つの選択肢がある。
- 外部の依存に対するすべての読み込みと書き込みをビジネス・オペレーションの始めや終わりに持っていく
- ドメイン・モデルにプロセス外依存を注入する
- 決定を下す過程をさらに細かく分割する
そのとき、次の 3 つのバランスが取れていることが重要
- ドメイン・モデルのテストのしやすさ
- コントローラの簡潔さ
- パフォーマンスの高さ
ただし、3 つのすべてを備えることは不可能で、2 つまでしかできない。
- 外部の依存に対するすべての読み込みと書き込みをビジネス・オペレーションの始めや終わりに持っていく -> パフォーマンスが下がる
- ドメイン・モデルにプロセス外依存を注入する -> ドメイン・モデルがテストしづらくなる
- 決定を下す過程をさらに細かく分割する -> コントローラの簡潔さを保てなくなる
パフォマーンスとドメイン・モデルのテストしづらさを犠牲にできないので、必ず「決定を下す過程をさらに細かく分割する」必要がある。
コントローラが複雑になっても、管理可能なレベルまで抑える。
解決策
- 確認後実行(CanExecute/Execute)パターンの適用
- ドメイン・モデルの状態を追跡するドメイン・イベントの利用
第 8 章 なぜ、統合(integration)テストを行うのか?
第 9 章 モックのベスト・プラクティス
モックのベストプラクティス
- モックの利用は統合テストに限定する(単体テストでは使わない)
- モックに対して行われた呼び出しの回数を常に確認する
- モックの対象となる型は自身のプロジェクトが所有する型のみにする
第 10 章 データベースに対するテスト
第 11 章 単体テストのアンチ・パターン
- プライベートなメソッドをテストすること
- テストを行えるようにするために、プライベートな状態を公開すること
- テストへのドメイン知識の漏洩
- 具象クラスに対するテスト・ダブルの作成