何を今更、なことかもしれないないのだけど、もしかしたらこれを知ることでTDD(Test-driven development)をやることのハードルが一気に下がる人がいるかな、と思ってメモ。 特に、ある程度プログラマとして経験があるけど、どうもTDDは慣れないという人向き。
“TDDとは、TDD以前に脳内や機上でやっていたことをコードに落とすことに過ぎない”
このことが解ってから、TDDをするのが一気に苦痛ではなくなり、むしろ楽しくなった。
TDDでなくても、コーディングをするとき、temporaryなテストコードを書いたり、目視でのチェックはしたりするものだろう。たとえば、一時的に変数の値をハードコードして挙動を変えてみて、それを目視で確認したり、printデバッグとかもその一部だ。
つまり、このtemporaryなコードや目視している部分をpermanentにするのがTDDで書くテストコードだということがわかった。
TDDであろうが、なかろうが、考えないといけないこと、やらないといけないことはたいして変わらない。たいして変わらないなら、テストコード書いておいた方が得。
テストコードがあれば、チーム内で技術や知識の共有もテストコードを通じてしやすくなるし、コードレビューだって、コードとテストがセットの方がやりやすいだとやりやすい。
単純に、テストファーストでやらないのは色々と損だよね。って感じ。
後は、おまけみたいなものなんだけど、自分でTDDしたり、人のTDDでしたコードを見たりして、いくつか思ったことをメモ。
1. TDDでコードや設計がきれいになるのは、プログラマをさぼらせないから
いいコードでないとテストが書きにいので、「いいコードを書くのをさぼれない」ってことになって、結果的にきれいなコードにはなりやすい。人はさぼるものなので、これ重要。
2. TDDのUnit Testは自作自演
TDDでは、テストコードを書く人と実際のコードを書く人は通常同じなので、どうしても自分の都合のよいテストコードを書いてしまいがち。また、仕様を誤解してても、その誤解したままのテストコードになって、テストは通る。もちろん、自作自演だからこそ、1.の恩恵を得れる。
3. ある程度の範囲に影響するリファクタリング時の動作の保証は微妙
Unit Testは、どちらかというとホワイトボックス的なテストなので、リファクタリング時にもあわせて変えないといけないことも多い。そのため、ある程度の範囲を直す場合、Unit Testだけでは不十分。動作の保証という意味ではブラックボックス的なcucumberみたいなテストも組み合わせないと厳しい。(もちろん自動化以外のテストも必要だけど、これは別の話)
これはTDDってよりUnit Testの話か。
4. テスト自体の知識も大切
当然なんだけど、TDDをするようなツールの知識だけではなくて、ある程度のテストの知識がないと良いテストは書けない=良いTDDはできない。テストの知識ってのはCOBOLの時代(もっと前かな)から変わってないような知識。境界値チェックとか(ちなみに、こういうの勉強するのに情報処理試験の勉強ってなかなか侮れない)。
単純な例を挙げると、ある条件での平均値を求める、と言ったコードに対するテストで、テストコードで使うテストデータがその「ある条件」のものしか用意してなく、「ある条件」以外のものを用意してないといったケース。この場合実際のコードの方に「ある条件」が抜けていてもテストは通ってしまう。超基本なんだけど、それすらできてないテストを見かける。
単体テスト仕様書を何百枚も手書きしていた世代のノウハウをゲットすべき(関係ないけど、Key-Value Storeな方面でもあの世代のノウハウって役に立ちそう)。
ちょっと逸れるけども、知識どうこうではなくて、手を抜いてしまっているダメなテストももちろんダメ。
たとえば、Rubyとrspecでの例になってしまうが、 foo.should_not be_nil を安易に使いすぎるとか。foo.should == something とちゃんと書けるようなケースなのに、should_not be_nil で手を抜く。
他にも、Mock/Stubを使いすぎて、何もテストしてない状態になっている、とか。笑い話みたいだけどたまにある。
こういうのは「自分が何をテストしているのか」というのをしっかり意識しないと陥りがち。
そういえば、「TDDは品質のためじゃない!」 と、でかい声で言ってる人でも、多分このぐらいのことは当然やってる人たちなんだろうけど、なんか誤解は与えそうだね。とは思った。
記事の内容についての質問、苦情、間違いの指摘等なんでもtwitterでどうぞ。 Tweet