はじめて学ぶテスト駆動開発(TDD)

テスト駆動開発(Test-Driven Development)とは、テストファースト、つまり最初にテストを書いてからコードを書く開発手法。日本における TDD の第一人者、@t_wada さんのライブコーディングを見て勉強したのでまとめる。

TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング - YouTube

ゴールは動作するきれいなコード

TDD のゴールは、動作するきれいなコード。「動作するきれいなコード」は、下記の2つに分割できる。

  • 動作するコード
  • きれいなコード

TDD では、先に「動作するコード」を作り、それをリファクタリングによって「きれいなコード」にしていくことで「動作するきれいなコード」にする。TDD は、テストによって動作を保証することによりリファクタリングをやりやすくする手法でもある。

TDD のサイクル

  1. 次の目標を考える
  2. その目標を示すテストを書く
  3. そのテストを実行して失敗させる (Red)
  4. 目的のコードを書く
  5. 2で書いたテストを成功させる (Green)
  6. テストが通るままでリファクタリングを行う (Refactor)
  7. 1〜6 を繰り返す

TODO リストを作る

まず、仕様を理解してタスクを分解し、TODO リスト(箇条書き)を作る。

テスト容易性を高くするタスク分解のスキルが必要。最初は難しいが、やってみるとわかってくる。『クリーンアーキテクチャ』などの設計の本を読むのも役立つ。

Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ)

テストを書く

TODO リストの中から一つを選んで、テストを書く。テストを簡単に書ける(テスト容易性が高い)ものからやるとよい。慣れてくると、テスト容易性とコードの重要度は一致させることができる。

  • 準備(Arrange)
  • 実行(Act)
  • 検証(Assert)
  • (後片付け)

検証 → 実行 → 準備 の順番にやるとよい。ゴールから逆算。

TODO リストからテストを書き出せない(リスト内容の抽象度が高すぎる)場合は、TODO リストの抽象度を下げる。

テストを増やすときは、メソッドごと増やす。assert を縦に並べない。理想的には、一つのテストメソッドに一つのアサーション

実装の歩幅

  • テスト → 仮実装 → 三角測量 → 実装
  • テスト → 仮実装 → 実装
  • テスト → 明白な実装

仮実装:テストを成功させるための最短距離の実装。きれいなコードでなくて構わない。

三角測量:仮実装から、別の値でも動くようにすること。

明白な実装:一気に実装。

テストコードのテストはプロダクトコードでやる。プロダクトコードに意図的に判別可能な誤りを入れてテストを失敗させるなど。サイクルの1周目は仮実装で OK。

リファクタリング

リファクタリングとは、一般的には「外部から見たプログラムのふるまいを変えないで、コードをきれいにすること」。

TDD の考案者 Kent Beckによると、「成功しているテストが成功しているままで、コードをきれいにすること」(コードにはテストコードも含む)。

テストの構造化とテストコードのリファクタリング

仕様とコードが頭の中にあるうちに、テストの構造化とリファクタリングまで終わらせる必要がある。

テストコードのリファクタリングは、プロダクトコードのリファクタリングよりは慎重にならざるをえない。リファクタリングも分解することで安全に進められる。

テストにはメンテナンスコストがかかる。テストを増やすのは簡単だが、減らすのはとても難しい。基本的に、テストを書いた本人しかテストを減らすことはできない。メンテナンスコストを下げるためにテストケースは減らしておく必要がある。

テストコードは、動作するドキュメントであるべきだ。テストコードから仕様が読み取れるようにしておかなければならない。テストを書くために抽象度を下げたものは、抽象度が高い(仕様が読み取れる)状態に戻しておく。