読者です 読者をやめる 読者になる 読者になる

テスト駆動開発について僕は誤解していた

テスト

 ここ数日 ruby をやってるんですけど、ruby といえばテストらしいので Test::Unit やら RSpec やらを調べてました。しかし僕はこれまでまともな TDD をやってこなかったので、先にテストとは何ぞや?TDD とは何ぞや?ってのを調べたりしていました。
 この記事は、ずぶの TDD 素人がテストについて知り始めたまとめです。


1. きっかけは RSpec のドキュメント
 そもそも RSpec の↓紹介文の冒頭から意味不明に感じたんです。

FAQ:「RSpec って、要は Test::Unit でやっていることを別の書き方にしただけでは?」
この FAQ への短い答えはイエスです。

『スはスペックのス 【第 1 回】 RSpec の概要と、RSpec on Rails (モデル編)』 Rubyist Magazine

 えっ... じゃあ要らんやろソレ。いちいち手作業でチェックするより、自動で間違い探しした方が早いからテストするんであって「assert を書くための文法変えたの用意したよ、カッコいいでしょ」的なモノわざわざ使わなくても、ねぇ。
 ... と思ったのが始まり。しかしちょっと甘かったですね。TDD は奥が深かった。


2. 「TDD のテストは自動実行できる assert の集合に過ぎない」という誤解
 どうもこれは間違いだったようです。@bleis さんの blog にハッキリ書いてありました。

もう一度言いますが、TDD のテストは Developer Testing であって、品質保証を目的としたテストではありません。なので、例えばカバレッジだとかを TDD のテストに対して求めるのは多分違っている。

『TDD の基礎体力と、TDD に対する想い』予定は未定Blog版

 えー(´Д` ) !? 品質保証しないで何がテストですか。TDD まじ分からん...。
 よく「プロダクトコードを書くより先にテストを書け」って言うじゃないですか。テスト書いてそれを満たすように設計することでそれぞれのプログラム部品の安全性が保証されて、最終的に製品の品質保証をする... というものでは無いの?


3. 「TDD のテストは設計を実コードより先に決定づけるものである」という誤解
 どうも TDD におけるテストを根本的に間違って認識していたようです。認識のズレを補正してくれたのは @irof さんの blog のこの文章でした。

TDDでは常にテストが付き纏います。うざいほどにいつも一緒です。
テストが思った通りに動く事に注意を払いながら、一歩一歩踏みしめて行ってください。テストはきっと応えてくれる事でしょう。
TDDはテストとのペアプロだと思います。テストと対話して行う開発スタイルです。

『テストと言うパートナー #TddAdventJp』日々常々

 テストは設計を決定づけるものではなく、テストは設計を実装に落とす作業のパートナーなんですね。よくプログラミングの手順の解説で、「関数の引数と戻り値を決めてから中身を書け」「クラスのインターフェイスを決めてから中身を書け」というのがありましたが、TDD のテストはこれらの延長線上にあるようです。つまり「テストを決めてから実装を書け」ということ。開発するときは、テストをちょろっと書いて、プロダクトコードをちょろっと書いて、またテストをちょろっと書いて... という具合に進めていくようです。プロダクトコードとテストが一緒になって製品をつくりあげてゆくわけです。
 これのイメージを掴んだことで、少しずつ TDD 関連の記事が理解できるようになりました。


4. 「テストとプログラミングをちまちま切り替えるより、それぞれ集中してやったほうが良くね?」という誤解
 たぶん↑これは素直な意見だと思うんですよね。
 テストコード書く時間だって馬鹿にならんのだし、どうせバグ出す人は出すんだったら、最後にまとめてテストした方がえぇに決まってるやん(´Д` )
 というのは誰でも考えると思います。しかし TDD では主に 3 つの理由を盾に、↑これを否定しているように読み取れます。
理由1. プログラマは不安である。故に、テストで不安を解消する必要がある。
理由2. きれいなコードが設計の質を上げる。故に、テストによってコード品質を維持する必要がある。
理由3. 開発終盤は重大なバグ修正に集中すべきである。故に、小さなバグ修正はテストによって序盤で潰す必要がある。
 ↑この 3 つは TDD の必要性を認識するためのキモだと思います。
 仮に TDD 抜きで開発してたら、こういう部分がないがしろになって、バグ出すしデスマするし担当者はいつも冷や汗かいてるし ...っていう負のスパイラルに陥るでしょ?いい加減、分かってるでしょ?そういう状況を避けるような仕事をしましょうよ?... ってことなんですね。


5. 「どうせテスト書いたってプログラム修正したらすぐ捨てるわけだし、やっぱりテスト書くのは時間の無駄じゃね?」という誤解
 僕、一生懸命、見やすいコード、変更に強いコード、書いてるつもりなんですけど?(´Д` )
 ここで一歩後に下がって、客観的にコーディングというものを見つめ直す必要があります。そもそもそういう「良いコード」を書く目的は、プログラムを正しく速く作るためですよね。正しさと速さは、「良いコードだけ」よりも「良いコードと良いテストのペア」の方が獲得しやすいんですよ。この観点が大切です。従って TDD においては、テストの修正とプログラムの修正の両方を行います。... ということを踏まえた上で↓このスライドを読むとぐぐっと理解できます。
 『ユニットテストの保守性を作り込む 〜設計・実装の工夫で支えるユニットテストの継続的活用〜』 SlideShare
 ↓ここらへんは押さえとくと良いですね。


P12:汚いコードをテストで保護する。
P17:動作がわからないものを扱う時の不安解消のためのテストと、用例のドキュメント化
P29:今やプログラミングとユニットテストは一体となっている
P31:可読性の悪いテストが抱える問題
P40:テストコードのレガシーコード化はテストの効果を反転させてしまう


6. 「テストにまで可読性を求めるとか、バカじゃね?」という誤解
 ここまでくれば、もう↑こういう誤解も無くなってきますね。テストにも可読性は求められるし、整理整頓されて然るべきです。たまに TDD やってる人が「日本語でテストを書きたい」と言ってるのも理解できますね。プログラマプログラミング言語に可読性・柔軟性・堅牢性を求めますが、TDD 実践者はテストに対しても同じものを求めているんです。
 僕は本稿の冒頭で RSpec の存在価値を否定しましたが、その態度はここへきてようやく否定できます。


7. TDD 実践のための、ひとつの図
 日本の TDD 第一人者の @t_wada さんが「これだけ覚えて帰ってね」と強調する図が↓これです。
 
 ↑この図の解説を含め、TDD のエッセンスを知るには @t_wada さんの↓このプレゼン動画を見るのが一番でしょう。
 『tddbc tokyo 1.5 基調講演』ustream



 以上、「ずぶの素人の僕が少し TDD を理解した気になったまとめ」でした。僕は、最後の動画を紹介するために本稿を書いたようなものです。それくらいメッセージ性の強い素晴らしいプレゼンです。

 というわけで、次回に続きます。