テスト駆動開発
また、テストコードから導かれるコード本体は、リファクタリングの過程によって、あるいはテストが成熟するに従って、最終的な目的とするコード本体のテスト用スタブに変わっていくかもしれない。早い段階でテストとコード本体を分離して管理するのはあまり意味がない。テストやコード本体が成熟していくにつれ、テストの記述が抽象的・間接的になり、リスクが導入される(例えば、フィールドを直接参照する代わりにgetterメソッドを使うなど)。しかし、テスト駆動開発のテストの目的は、開発者の正しさへの確信を裏づけするためであり、それが保たれているならば問題はない。
テスト駆動開発で用いられるテストは、品質のためのテストではない。したがって、コード本体とは独立してあらゆるケースを網羅するテスト、すなわち「テストそのものが価値を持つようなテスト」を目指しているわけではない。テスト駆動開発におけるテストとは、コード本体とテストを合わせて検討することで、開発者がその正しさに確信を得るようなものである。したがって、開発者の確信に少しも寄与しないテスト(また、ドキュメントとしてテストの読者に何かを伝えるために書かれていないもの)は、むしろ積極的に削除を検討する。
テスト駆動開発を実施するには、テストを自動的に実行できる環境が必要である。そのような環境としては、JUnitやNUnitといったもの(総称してxUnitとされる)が挙げられる。なお、このテスト実行環境は、コンセプトが単純であり、かつ非常に強力であることから、実行環境そのものをテスト駆動開発で自作するのもよい。ただし、そのテストツールをテストするツールはないことから、しばらくは慎重な人の判断でもってテストの代わりとすることになる。
最も基本となる開発サイクルは以下のようになる。
失敗するテストを書く
できる限り早く、テストに通るような最小限のコードを書く
コードの重複を除去する(リファクタリング)
なお、テストの実行環境ツールであるxUnitでは、テストの失敗を赤いバー、成功を緑のバーで通知するため、上記のサイクルは Red/Green/Refactor と称される。
より実践的には、to-doリストを組み合わせることにより、以下のような手順で開発する。
まず、現時点で分かっている範囲で、テストする必要がある項目を列挙する。なお、このリストは、テストの必要性がわかった時点で適宜項目を追加していく。
このリストから1つ選ぶ。これは、実装できそうでかつ重要なものを選ぶ。このとき、テストの記述が容易でも、Fake It(後述)でしかコードを記述できなさそうなものは後回しにする。実装できそうなものがない場合は、列挙した項目の粒度が大きすぎることを意味する。そのため、そのテストを実装するための前提となるような、より小さい粒度の項目を作成し、それをリストに加える。
選択した項目について、テストを作成する。このテストは、現在の実装を用いると失敗するように記述する。
コンパイルに必要な最小限のコード(例えば、まだ存在しないクラス・メソッドを利用するテストを作成した場合であれば、そのクラス・メソッドの宣言)を追加した後、実際にテストを実行し失敗することを確認する。期せずしてテストに通った場合は、意図しないことが起こっていることに注意し、テストが失敗するまでコード本体を変更しない。
できる限り早く、テストに通るようにコード本体を記述する。