テスト駆動開発とは?

テスト駆動開発の手法と用意されたテストスイートを使って演習を解きましょう


テスト駆動開発(テストファースト開発、テスト駆動設計と呼ばれることもあります)とは、実装コードを1行も書く前に、まず単体テストを書くという開発手法です。

Exercismでは、テストこそが_要件_です!

取り組むすべてのプラクティス演習(新しい概念を学ぶものではないほうの演習)には、何をする必要があるかを一般的な言葉で説明した指示があります。 この指示は設計上、プログラミング言語固有の実装の詳細までは扱いません。Exercismの70以上ある言語トラックすべてで共有されているものだからです。 トラックによっては、より具体的な詳細が追加されていることもありますが、そうでないトラックもあります。

プラクティス演習に取りかかるときは、指示をよく読んでください。 指示には、解答をどのように実装していくかの大まかな全体像が書かれています。 ただし、完全で正確な要件を理解するには、_テスト_を読む必要があります。

  • 結果は特定の種類のデータ構造でなければならないのか?
  • 結果は何らかの順序で並べ替える必要があるのか?
  • 例外はどう扱うことが求められているのか、などなど。

用意されたテストがすべて実行されて通れば、その演習は解けたことになります。 言い換えれば、解答は指示を「それらしく」解釈したものでは済みません。解答は、_与えられたテストを満たす_プログラムです。 テストが、その演習の完全な要件を表しています。

ExercismではTDDをどう実践しているのでしょうか?

単体テストスイートを書く作業は、こちらで済ませてあります。 目指すのは、それらの単体テストをすべて通すのにちょうど足りるだけのコードを含む解答を書くことです。

覚えておいてほしいのは、TDDの進め方は解答にたどり着く助けにはなりますが、そこで止まる必要はないということです。 要件を超えて解答を発展させたいなら、ぜひそうしてください。 メンターと一緒に取り組むことを選ぶなら(テストが通るようになったら、ぜひそうすることをおすすめします)、最初の実装をリファクタリングして磨き上げるのを手伝ってくれますし、新しい単体テストを提案してくれることもあります。

オンラインエディターで作業する

Exercismのウェブサイトにあるコードエディターで作業しているときは、テストを読むことはできますが、編集することはできません。 テストファイルに書かれている「スキップ」の仕組みに関係なく、実行するたびにすべてのテストが実行されます。

失敗するテストが複数ある場合、ウェブサイトは最初、最初に失敗した結果だけを表示します。 ほかの失敗をクリックして展開することもできます! 最初の結果が必ずしも一番参考になるとは限りません。

失敗するテストが多いからといって、落ち込まないでください。 一つずつ通していくことに集中しましょう。

ローカルで作業する

多くのトラックでは、テストファイルで「スキップ」されたテストを使っています。 最初は、最初のテストだけが「有効」で、残りは無効です(これがどう行われるかはトラックによって異なります)。 自分の環境でテストスイートを実行すると、最初のテストだけが実行されます。 これは、次の流れに沿って進めてほしいからです。

  1. 新しいコードを追加する前に、テストスイートを実行します。失敗するテストが確認できるはずです。
  2. テストを通すのに_ちょうど足りるだけ_のコードを追加します。
  3. テストスイートを実行します。
  4. それでもテストが失敗するなら、手順2を繰り返します。
  5. テストが通ったら、有効なテストがすべて通り続けることを確認しながら、コードを好きなようにリファクタリングします。 リファクタリングには、たとえば次のようなものがあります。
    • 重複したコードを取り除く
    • 長い関数を小さな関数に分割する
    • コメントを追加する、など
  6. 次のテストの「スキップ」を解除し、手順1から繰り返します。

すべてのテストのスキップを解除するまで、この手順を繰り返します。 すべてのテストが通ったら、おめでとうございます。その演習は解けたことになります!

テストのスキップを解除する(つまり有効にする)正確な方法は、トラックによって異なります。 トラックによっては、アノテーションをコメントアウトしたり削除したりします。 またトラックによっては、属性をtrueからfalseに変えることもあります。 時間を取って自分のトラックのドキュメントを読んでください。詳しいことはそこに説明されています。

テストをスキップしないトラックでは、この流れを実践するのは、テストをコメントアウトして一つずつコメントを外していくだけかもしれません。

テスト駆動開発の理由

「本末転倒」のように思えるかもしれませんが、実装コードを書く前に単体テストを書いたほうがよい理由はいくつかあります。

  1. 設計。 コードの実装方法にいきなり飛びつくのではなく、まずプログラムのインターフェース(機能を外の世界にどう公開するか)について考えることを強制されます。 よく設計された(そしてテストしやすい!)インターフェースは、効率のよい実装よりも重要であることがよくあります。

  2. 規律。 テストを書くことは、面倒な作業や後回しにするものと見なされがちです。テストを_先に_書けば、その日の終わりには、コードの機能の大部分、あるいはすべてをカバーするだけの単体テストが書けていることが保証されます(いつまでも手をつけられずに終わる、という事態を避けられます)。

  3. 作業量の削減。 テストを1つ書く、そのテストを通すコードを書く、次のテストを書く、というサイクルを細かく回していくと、コードは自然に育っていきます。 こうすると多くの場合(いつもではありませんが)無駄な労力が減り、必要なコードはすべて書き、不要なコードは書かずに済みます。

参考資料