TDD(テスト駆動開発)とは?そもそもテストって何のためにある?

テスト駆動開発を勉強しています。
誰かさんいわく、「テスト駆動開発は「恐れ」を乗り越えるためにある」らしいです。
テスト駆動開発について学んだことをまとめてみます。

そもそもテストってなぜ書くのか?

そもそもテストってなぜ書くのでしょうか?
調べてみたところ、テストを書くということには多くの目的があるようです。
一つずつ見ていきます。

プログラム自体が壊れていないことを保証するため

大規模なプログラムを毎回手作業で、全て問題ないかをチェックするのは非現実的です。
そこでテストの出番です。
テストさえしっかり書いておけば、「テストが通る=プログラムが壊れていない」ということの証明になります。

つまり、テストはプログラムの安全を保証してくれるということです。

安心してリファクタリングを行えるようにするため

期待する動作のテストを書いてそのテストが成功している場合、自信を持ってリファクタリングを行うことができます。
リファクタリング後はテストが通ることを確認すればいいだけです。

期待する動作は変わらず、中のコードだけをスッキリさせることができます。
こうすることで可読性や保守性が高まり、将来の開発工数を短縮できるようになります。

動作確認を自動化するため

プログラムを少し変更して毎回目視で確認するのは大変すぎてとても非効率です。
そこでテストで確認作業を自動化します。
こうすることで大幅に作業効率が上がります。

バグの再発を防止するため

バグが発生した時、バグを潰すテストを真っ先に書くことでバグの再発を防止します。
テストさえしっかり書かれていれば二度と同じバグは発生しません。

同じ不具合を二度と起こさないことは、顧客や利用者からの信頼を守ることにつながります。

仕様書としての役割

テストは「開発者がプログラムに期待する動作の塊」なので、それを見るだけでプログラムのあるべき姿が分かります。
これは「プログラムの仕様書」とも言い換えることができます。

つまりテストは仕様書の役割も果たすので、他のメンバーや将来の自分がテストを見るだけでプログラムのことを理解しやすくなります。

TDDのやり方

TDDは必ずテストを書いてから実装に入るやり方です。
テストファーストの手法と言われます。

TDDの基本的なやり方は

  1. ゴールを設定する
  2. ゴールから逆算してテストを書く
  3. 実装する

という流れです。
詳しくは以下のサイクルを短期間で何度も回します。

TDDのサイクル(Red, Green, Refactorのサイクル)

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

これを何度も繰り返すのがTDDです。

また毎回ゴールから考えるので、やってみると分かりますが、期待する動作を達成するにはどうすればいいかをかなり細かいところまで考えることになります。
これはいわば、プログラムを書く前に毎回設計をしているということになります。

つまり、テストから先に書くことで設計の良し悪しに気づくことができるようになります。

TDDの最大のメリット

大きなメリットは開発者にとって「開発が進んでる感」を得られることにあるようです。

以下引用です。

自分の作業がきちんと達成できていることを、テストで即時に確認できるようにします。
例えばテストコードを追加したら、テストの失敗をチェックすることでそのテストが動いていることを確認します。プロダクトコードを追加したら、テストコードが失敗から成功に変化することをチェックして、実装が問題なく達成されていることを確認します。リファクタリングを行ったら、テストの結果が変化していないことをチェックすることで、意図しないバグや副作用が混入していないことを確認します。
テスト駆動開発では、こうしたフィードバックを数十秒から数十分の超短期で得ることにより、プログラミングミスを即時に検出できるようにします。なおこのメリットはプログラマに「プログラミングは順調だ」という安心感を与えることから、ケント・ベックや和田卓人氏などテスト駆動開発のエバンジェリストは、しばしばテスト駆動開発を「心を健康にする手法」等と紹介することもあります。

つまり、この「進んでる感」を短期間で何度も得ることにより、開発が順調であるという安心感が得られることが最大のメリットを言えそうです。
まさに「心を健康にする手法」ということですね。

実践あるのみ

こういうの理論だけがわかっても意味がないので、実際にやってみるしかないですね。
今度からは「テストを書く→実装する」という流れで開発を進めるようにしてみます。