より実践的には、to-doリストの利用を組み合わせた以下の手順で開発を行う。
*まず、現時点で分かっている範囲でテストの必要性がある項目をリストとして列挙する。このリストは適時、テストの必要性がわかった時点でその適宜項目を追加していく。
*このリストから1つ選ぶ。これは、実装できそうなものでしかしトリビアルでつ重要ないものを選ぶ(テスト自体の記述が容易でも、Fake It(後述)でしかコード本体を記述できなさそうなものは後回しにする)。実装できそうなものが無ない場合は、列挙した項目の粒度が大きすぎることを意味する。その場合、それを実装するための前提にできとなるような、より小さい粒度の項目を作り成し、それをリストに加える。
*選択した項目についてテストを記述する。このテストは、現在の実装を用いると失敗するようなものを選ぶ。
*コンパイルに必要な最小限のコード(例えば、まだ存在しないクラス・メソッドを利用するテストを書いたなら、そのクラス・メソッドの宣言)の追加後、実際にテストを実行し失敗することを確認する。期せずしてテストがパスした場合は、意図しないことが起こっていることに注意する。テストが失敗するまでは、コード本体は触らない。
**テストに要求される値そのものをハードコーディングする(Fake It;仮実装)。
**Fake Itの後に次のリファクタリングの段階へ進めないような漠然としている場合は、さらに別のデータを用いたテストを追加し、その2つのテストの共通点を見出して助けとする(Triangulate;[[三角測量]])。
*テストがパスす通ることを確保持しつつ、コード本体やそれ自体やコードとテストの間のにある明示的・暗黙的な重複を取り除く(リファクタリング)。通常、リファクタリングとは、コードの意味を変えずにコードを再構築することを言いうが。なお、ここでは、の「コードの意味」とは、テストが通ることを言う。また、リファクタリングで取り除く対象となる重複は、形式的なものだけではなく、意味的なものも含むまれる。例えば、Fake Itでハードコーディングしたものは、おおよそ、実際にはどこからか得られるはずのパラメータの値を、それとは別にの値を用いて算出したものでありるため、これを重複と見なす。そして、重複を取り除くことで、ロジックが抽出される。
*リストから実装した項目をリストから削除する。このとき、作業中にテストのする必要性が判明しあるとわかった他の項目に、実質的に振り変わるかもしれない。
テストコードは、最初から自明であるとは限らない。むしろ、コード本体と同様、最初は具象的なテスト(例えば、単なるフラグの確認)を行い、これによって知見を得た後にテストを書き直して良たほうがよい。また、テストコードから導かれるコード本体は、リファクタリングの過程によりって、あるいはテストが成熟するに従いって、最終的な目的とするコード本体のテスト用スタブに変わっていくかもしれない。早い段階でテストとコード本体を分離して管理するのはあまり意味が無ない。テストやコード本体が成熟していくにつれ、テストの記述が抽象的・間接的になり、リスクが導入される(例えば、フィールドを直接参照する代わりにgetterメソッドを使うなど)。しかし、テスト駆動開発のテストの目的は、開発者の正しさへの確信を裏づけするためであり、それが保たれているならば問題はない。
テスト駆動開発で用いられるテストは、品質のためのテストではない。したがって、コード本体とは独立にしてあらゆるケースを網羅するようなテスト、すなわち「テスト自体でそのものが価値を持つようなものはテスト」を目指しているわけではない。テスト駆動開発におけるテストとは、コード本体とテストを合わせて検討することで、開発者が、その正しさに確信を得るようなものである。したがって、開発者の確信に少しも寄与しないテスト(かつまた、ドキュメントとしてテストの読者に何かを伝えるために書かれたものではていないもの)は、むしろ積極的に削除を検討する。
テスト駆動開発を実施するには、テストを自動的に実行できる環境が必要である。そのような環境としては、[[JUnit]]や[[NUnit]]といったもの(総称して[[xUnit]]とされる)が挙げられる。なお、このテスト実行環境は、コンセプトが簡単なわ純でありに、かつ非常に強力なツールであることから、新しい言語実行環境そのもの習得を兼ねてそれ自体をテスト駆動開発で自作するのもよい。ただし、そのテストツールをテストするツールは無ないことから、しばらくは慎重な人の判断でもってテストの代わりとすることになる。
==利点==
|