Skip to content
Latchkey

テスト駆動開発(TDD)とは?

テスト駆動開発は、望む振る舞いに対して失敗するテストを、それをパスさせるコードを書く前に書くワークフローです。

テスト駆動開発、略してTDDは、通常の作業順序を逆転させます。コードを書いてからテストを後付けするのではなく、望む振る舞いを失敗するテストとして記述し、それをパスさせるのにちょうど足りるコードを書き、そして整理します。この規律は、機能を作る副産物としてテストのセーフティネットを生み出します。

レッド・グリーン・リファクタのサイクル

TDDは緊密なループで進みます。まず、機能がまだ存在しないために失敗するテストを書きます(レッド)。次に、それをパスさせる最もシンプルなコードを書きます(グリーン)。最後に、テストをグリーンに保ったまま、コードとテストをリファクタして重複を取り除き明快さを高めます。各ループは小さく、しばしばわずか数分です。

なぜテストを先に書くのか

テストを先に書くことで、始める前に「完了」の意味を定義せざるを得なくなります。テストしにくいコードは通常使いにくいため、小さくテスト可能なユニットと明快なインターフェースへと後押しされます。失敗するテストはテストが失敗しうることも証明するので、後のグリーンな結果が実際に意味を持ちます。

実践例

2つの数を足す関数が必要だとします。まず、add(2, 3)が5を返すことをアサートするテストを書きます。実行するとaddが存在しないため失敗します。関数を書き、テストを実行するとパスします。次に負の数のテストを追加して繰り返します。

A first red-green step
test("adds two numbers", () => {
  expect(add(2, 3)).toBe(5);
});

function add(a, b) {
  return a + b;
}

TDDが得意なことと苦手なこと

  • 強く適合: 純粋なロジック、パーサー、計算、明確に定義されたユニット。
  • 適合が弱い: 探索的なUI作業や、形がまだ不明なコード。
  • ほぼ無料で高速なリグレッションのカバレッジを生み出します。
  • テストツールであると同時に設計ツールです。

TDDと継続的インテグレーション

TDDは高速で決定論的なテストスイートを残すため、CIと自然に相性が良いです。すべてのpushが開発者がローカルで実行したのと同じテストを実行するので、pull request上のグリーンなbuildは希望的な推測ではなく、実際の意図した振る舞いを反映します。

ループを高速に保つ

TDDは、ローカルでもCIでもフィードバックループが短いままである場合にのみ機能します。スイートが大きくなったら、より高速なrunnerで並列に実行することで、各pushを1、2分以内に保てます。Latchkeyはそのスイートを高速なマネージドrunnerで実行し、それらに分割することで、開発者がコンテキストを失う前にグリーンなチェックが届きます。

重要なポイント

  • TDDとは、それを満たすコードの前に失敗するテストを書くことを意味します。
  • レッド・グリーン・リファクタのループは、進めながらリグレッションのカバレッジを構築します。
  • 小さくテスト可能なユニットを好む設計ツールとしても機能します。

関連ガイド