ユニットテスト
ユニットテストの目的
関数/メソッドの説明書として
- 関数/メソッドがどのような使われ方を想定しているかをコードから読み解くのは中々難しい
- 実際の利用例が最も分かりやすい
- また、取り得る入力のエッジケースや出力の変化もテストコードが生きたドキュメントとして機能する
テストダブル
テストダブルとは
- テスト対象が依存しているコンポーネントを置き換えてテストを容易にするテスト時のみ使用するコンポーネント
- ダブル(Double)とは代役、影武者を意味するらしい
- 映画のスタントマンのことをスタントダブルと呼んでいたのが由来とのこと
種類
WEBアプリケーションのテスト戦略
- ハンドラ層はビジネスロジック層をモック化してハンドラ層のみテスト
- ビジネスロジック層は永続化層をモック化してビジネスロジック層のみテスト
- ドメインモデルは基本的にテストは書かないが、ロジックが複雑なものに関しては書く
- 永続化層のコードのテストは書かない
- 永続化層の担保はE2Eテストで行う
ユニットテスト不要論
(1) ユニットテストのコストが利益を上回る
- ユニットテストの作成・保守・実行には時間と労力がかかり、そのコストが得られるメリット(バグの早期発見、コードの信頼性向上)を上回る
- 小規模プロジェクトや迅速なプロトタイピングでは、ユニットテストを書くよりもコードを直接本番で試す方が効率的
- テストのメンテナンス負荷が受け入れがたいレベルに達する
- 過剰なテストコードが作成されがち
(2) インテグレーションテストやE2Eテストで十分
- コンポーネント単位のテストより実際に統合されたアプリ(システム)の振る舞いの方が重要
- ユニットテストではなくインテグレーションテストやE2Eテストにリソースを割くべき
- 実際に動くシステムを使ってテストする方が低コストでバグを発見できる
(3) 本番環境でのモニタリングやカナリアリリースが代替
- 本番環境で素早く問題を検知・修正・リリースできる体制が整えられているなら、ユニットテストでバグを防ぐよりも積極的に本番環境にリリースした方がよい
- 特に市場の反応に迅速に対応する必要のあるサービスなら多少のバグよりも早く市場に公開できることの方がメリットが上回る
(4) ユニットテストがコードの硬直化を招く
- ユニットテストを書くと、テストコードの資産を活かそうとして設計変更より既存コードの修正を選んでしまいがち
- テストを通過させる為にコードを書くという逆転現象が起きてしまう
- 実装の詳細に踏み込んだテストコードがある場合、実装やインターフェイスが変化した場合、テストが大量に壊れてしまう
(5) 開発者のスキルやコンテキストに依存
- テストコードの品質は開発者のスキルやプロジェクトの性質に依存する面が大きい
- 小規模なプロトタイピングのプロジェクトではテストコードを書いても有効に機能しない上、工数が無駄になってしまう
(6) ユニットテストには限界がある
- ユニットテストでは全てのバグを防ぐことができない
- 境界条件や外部システムに依存する問題を防ぐには向いていない
- モックを多様するテストでは実際のコードの検証が漏れていて、本番環境までバグが残ってしまうことが見受けられる
- 複雑過ぎる構成のテストコードでも同様の問題が起きる
- 結局、インテグレーションテストやE2Eテストで検出するしかない問題もある