はじめに
最近テストコードについて言及することが増えてきたので、テストコードについての自分の考えを伝える上で、整理したいと思って言語化してみた。
基本的に既にテストに詳しい方が書いた本やWebページはいろいろあるのでそちらを推奨する。
本稿についてはUT/IT/E2Eなどの違いについては言及しない。
なぜテストが必要なのか?
大前提として「バグのないシステムは作れるか?」ということを考える。
ここでは非常にシンプルなプログラムを除いて業務で作るようなことを前提とするが、私の答えとしては「できない」である。
正確には作れるかもしれないが、それを証明するのはシステムの規模や複雑さに応じて困難である。
テストとは証明である。
それは人間がやる場合でもテストコードの場合でも同様である。
そしてテストで証明できることとして、
- ある動作が正常に動くこと
- ある動作が正常に動かないこと
などが挙げられる。しかし、バグーーーつまり意図しない挙動を発生させることは難しい。
- バグがあること → 想定しているパターンにバグがあればできる
- バグがないこと → 悪魔の証明。全てのパターンを洗い出す必要がある
テストを含む要件定義や設計などは人間が行うため、ミスが避けられない。
結論としてテストが必要な理由は以下により、一定の品質保証するためである。
- できることを証明する
- できないことを証明し、それを改善する
逆に言えばテストが行われていないものは、無保証のため、信頼性が低いと言える。
テストは品質保証の手段。具体的なやり方は多様
前述の通り、テストは品質保証のための手段である。
高い品質を保証をするため、何種類ものテストや何段階かのテストを行う。
- テストコードによる自動テスト
- 単体テスト
- 結合テスト
- E2Eテスト(エンドツーエンドテスト)
- 人間による手動テスト
- 例) 環境による違い
- 開発環境
- 検証環境
- ステージング環境
- プロダクション環境
- 例) 環境による違い
※ テストと別であるが同じようなものとしては、人間によるコードレビューや静的チェックによる構文や意味解析による自動チェックなども品質保証の手段として用いられる
観点や目的、環境などによってテストにはいろいろな種類のテストがあり、それらを何種類か行うことで少しでも高い品質を保証する。
当然ながらテスト自体にもバグやミスがあるので、1回のテストよりも何種類か、または何人かでテストした方が高い品質を保証できる。
ただし、テストは準備や実施にコストが掛かるため、無制限にテストを行うことは現実的でない。
そのため、テストでは、どれだけコストを抑えて、どれだけ高い品質保証をできるかが重要になる。
2つの観点を更に言及すると以下のような内容が挙げられる。
- コスト
- 準備コスト
- テストパターンの調査・検討
- テストを実施するために必要な準備
- テストコードの追加
- 実施コスト
- テストを行うための時間や手間
- メンテナンスコスト
- リファクタによる影響でテストコードを修正する
- 機能追加・改修によるテストコードの改修
- 準備コスト
- 効果的な品質保証
- 本番(実際の動作)に近い検証である ※ 本番でありえないものを保証しても価値は低い
- 十分なパターンが検証される ※ どれだけ保証されているかで信頼性は増す
テストコードのコスト
同じように人間がテストする場合でも観点によっては評価が変わることはある。
例えば異常パターンをテストする場合、エラー文言を確認する程度であればテストコードやIDEのデバッグ機能などで無理やりエラーを確認する方が簡単なこともあれば、不正操作によって人間が直接操作した方が早いこともある。
とはいえ、傾向としては、人間が行った方が本番に近い検証ができ、逆に実施コストは人間によるテストよりもテストコードによるテストが優れている。
当たり前のことだが、テストに限らず、プログラムである以上、一度書かれたプログラムを再度実行するのは圧倒的に容易だからだ。
そのため、実施コストや準備コストについては長期的に考えると、テストコードの方が優れていると考えられる。
では、同じテストを何度も実行する理由は何かというと以下のようなことが挙げられる。
テスト | 説明 |
---|---|
リファクタのためのテスト | 同じ仕様でコードを変えた場合に仕様が変わってないことをテストする |
リグレッションテスト | 別の機能の改修、仕様変更により元の挙動で意図しないバグが発生していないかを確認するためのテストする |
多くの場合、一度作成したアプリが変更されないことは滅多にない。
実装期間中に何度もコードを直したり、テストで見つかったバグの対応だったり、仕様追加や改善のために変更したりと、いろいろな理由でコードが変更される。
アジャイル開発の場合は、小さい変更を積み重ねて開発を行うため、より多くのコード変更が行われる。
リグレッションテストについては明らかに不要な場合は省略することが多いが、省略することを判断するためには設計やコードを読む必要な場合がある。
そのため、それらを判断しなくてもテストを実施可能であれば、その分効率が良い。
ただし、メンテナンスコストによっては当然ながらそのコストの優位性が失われることは考えられる。
メンテナンスをしないための最も簡単な方法はそもそもテストコードを追加しないことである。
しかし、最初に言った通り、テストがないコードは無保証の信頼できないコードである。
また、リグレッションテストの観点から言えば毎回確実に影響調査をしなければならないコードと言える。
つまり、テストコードがないコードは改修コストが高く、メインコードのメンテナンス性を下げている。
テストコードの良し悪しを判断するための判断指標
テストコードがないコードは改修コストが高く、メンテナンスが大変なテストはその分のコストが掛かる。
すなわち、テストコードはメンテナンスが低く、かつリファクタやリグレッションに備えた十全なテストであることが望ましい。
これらを踏まえると、テストコード全般には以下のような指標で良し悪しが考えられる。
- メンテナンスコストが低いこと
- 本番(実際の動作)に近い検証であること
- 十分なパターンが検証されること
これらを実現するための具体的なやり方は別途言及する。