はじめに
テスト駆動開発(TDD)について、「実践テスト駆動開発」を元にまとめてみようと思いました。全てをここでアウトプットすることはできないので、自分が常日頃TDDについて感じていることを書籍を読みながら整理していきます。
なぜテスト駆動開発(TDD)が必要なのか
テスト駆動開発の基礎的なプラクティス(テストを書いて、実行する)は実践しているものの、結果を出せずに苦しんでいるチームがある。表面的な理解で、ただやるだけでは機能しないことが分かる。ではこのTDDの真髄はどこにあるのか。
オブジェクト指向ソフトウェアを「育て」、より良い品質のコード作成はテストによって「導かれる」
ソフトウェアは常に動く状態にしなければならない。しかし、これは「言うは易し。行うは難し」で実際のコードは複雑なコードが多くの箇所で書かれており、保守をするのは大変だ。ただ、これは整備されていない場合の話。TDDを実践していると、動いているシンプルなシステムが相互に作用するようになっている。つまり、生物学的な細胞のようにメッセージを送りあっていて、より巨大なシステムを構成したいと思ったら、一つ一つが多くのところで活用される(育てる)ようになる。
そんなシンプルでかつシナジーを出せるようなコードを作るためには、TDDしか道はない。良いコード作成の前には良い設計がある。TDDはその設計を明確にしてくれる。テストを先に書くことで自分の意図を明確にしなければならないからだ。コーディングをどうすべきかを自分が曖昧にしか言語化できないうちは作業に着手できなくなる。テストを先に書くと言うプロセスに従うことで、自分の狭い視野や凝り固まった考えをテストによって自覚することができる。リファクタリングでも、同じデグレが生じないようにテストが支えてくれるのだ。
TDDのメリット
テストを使ってコードに「何を」させたいのかというアイディアを明確にすることができる。そして、そのアイディアの質はテストを先に書くことによって迅速なフィードバックが得られる。つまり、実装に入る前により良い設計を早いフィードバックサイクルによって実現することを可能にするのだ。
受け入れテストとユニットテストの役割とは
テストをしているとしばしばこの2つを耳にする。両方やらなければならないことは分かっているが、それぞれが何を担保しているものなのかいまいちよく分からなかった。しかし、今回の学びでそれが明確になった。
外側の質と内側の質
外側の質とはシステムが顧客やユーザーのニーズ(機能を備えているか、信頼できるか)に応えられているか、内側の質とは開発者や管理者のニーズ(理解しやすいか、変更しやすいか)にどれくらい応えられているか。エンドツーエンドテストではドメインについてどれだけ理解しているかについての知見が得られるが、コードの質については分からない。それを担保してくれるのがユニットテストで。多くのフィードバックを得ることで高品質のコーディングを可能にする。
振る舞いのユニットテストを行え、メソッドをテストするのではない
テストに限らず、コーディングでは常にリーダブルでなければならない。自分だけが分かるコードを書いても、他の人が読みづらかったり、理解しづらかったりするとリファクタリングコストが高くなってしまう。テストでも同じだ。例えば、testGetAccount()
という名前のテストでは何をしているかは分かるが、「何のために」 テストしているかが分からない。そのテストケースでは、対象のオブジェクトはどうあるべきなのかという 「振る舞い」 に焦点を当てたテスト名を書くのが望ましい。
まとめ
今回はテスト駆動開発の基礎の基礎をまとめました。書籍の5%くらいのことしか整理できていないと思っています。ただ、自分がやっていることが何のためのものなのか、目的が明確になったことが自分にとっての学びでした。引き続き読み込むことで、より良いテスト駆動開発を目指していこうと思います。