2011年10月17日月曜日

リファクタリング再読 4章 テストの構築

このブログで、何度も引用してきたけど、10年以上前に読んだリファクタリングが、今読んでも面白い。

面白いと言っても、当たり前の事が普通に書いてあるだけなんだけど、忘れた頃に読み返すと、自分が現場でいつも言っている事と大部分一致していて、若い頃に受けた影響ってやっぱりずっと残るんだと実感する。(さすがに、このレベルの名著ですら、やはり10年も経つとある程度の陳腐化は避けられず、全てに同意はできるわけではないけど…)

今日は 『4章 テストの構築』から、何点か引用して考えてみたい。

====

テストを完全に自動化して、その結果もテストにチェックさせること。(P.90)
xUnit Patterns の言葉で言うと、Manual Interventionは止めようねって事で、まあ、JUnitの基本中の基本。とはいっても、@Test メソッドの中で普通のアサーションで書ける比較を、標準出力に書き出して目視確認してたおバカさんを、こないだ発見した。こんなレベルの人が「JUnit 使用歴○○年です!」なんつってプロジェクトに入り込んできちゃったりするから、この業界っておそろしい。


テストを頻繁に実行せよ。コンパイル時にはテストを局所化して、一日に最低一度は全てのテストを実行せよ。(P.94)
今は普通に CIサーバでコミット時にテスト走らせたり、incremental test とかも普及してるから、一日一度はさすがに10年前って感じがするが、なるべく頻繁に実行すべしってのが、この文の趣意。まあ、なんぼ言っても、他人のテストコードをコケさせておきながら、コンパイルが通ってるってだけでテストもせず、平気でコミットする間抜けが減るどころか永遠に増え続けてるから、気が滅入るが…。


バグレポートを受け取ったら、まずそのバグを明らかにするための単体テストを書け。(P.97)
これは今も昔も良いプラクティスで、余り反論する人を見たことがないけど、数年前までは、いざバグを再現させるテストコードを書こうにも、そもそもテスタビリティが低すぎて、異常に難易度が高い場面もあった。今は、instrumentation を活用したテストフレームワークが普及しているから、そうでもないけど。(テストツールのテスト能力が高まっただけで、ソースコードのテスタビリティは大して進歩していないのが悲しいが)


ここでお話しするのは「単体テスト」です。これはプログラマの生産性を向上するために行うものです。これで品質管理部門が満足するとしても、それは副作用に過ぎません(p.96)
リファクタリング〜xUnit の文脈の中で、「機能テスト」と対置されて語られる「単体テスト(UnitTest)」って、ウォーターフォール・モデルの単体テストを単に自動化しただけのものとはかなり違うんだけど、この勘違いは今でもかなり根強い。 自分が、現場で説明する時には、「外部品質じゃなくて内部品質をあげるためのツールだから」とか言う事がある。分からない人はどう言い換えてもやはり分かってくれないけど、わかる人はなるほどそうかと納得してくれたりする。


不完全なテストでも、書いて実行する方が、実行できない完全なテストよりもましだ。
テストを書けば自分が楽になるって認識が成立しないとプログラマはテストを書きたがらないわけで、つまり下手なプログラマって、テストコードによって自分で自分の作業を楽にする事ができないプログラマなんだけど、その手の輩に無理やりテストを書かせようとするから無理なカバレッジ基準が制定されて、後付けでパスを通そうとするから、却って生産性が下がる。そんなのどうせ、まともなアサーションが書かれるわけないのにさ。

本当は、自覚して UnitTest を使えてるプログラマが、どこにどの程度テストコードを書くか自分で判断すればいい事なんだけど、最低辺も含めて、いろんな人が集まるプロジェクトでは、うーんやっぱ難しいのかな…


大事な事は、一番怪しいと思う部分をテストすることです。それが最も効率の良いテスト方法です。(p.97)
失敗の恐れのある境界条件を考えて、そこを集中的にテストせよ。(p.99)
失敗すると予想される時に、例外が上がることをテストし忘れないこと。(p.100)
境界条件や例外条件なんかをテストするにしても、テスト駆動/テストファーストでやるのが、結局は一番楽で確実なんだけど、現場のレベルによってはいくら言い聞かせても浸透しない。後付けでテスト書いたって、カバレッジだけに必死になって、どこが「怪しい」かなんて完全に眼中の外になってしまう事が分かりきってるんだけどね。


テストで全てのバグが見つからないからといって、テストを書くのを止めてはならない。ほとんどのバグはテストで補足される。
そもそも開発者が要件を誤解していたり、忘れていたりしたら、そういった認識エラーは本体コードと同様にテストコードにも織り込まれてしまうから、開発者テストだけで捕捉するのは論理的に不可能。そういった限界がある事を認識した上で、機能テストも絡めた全体的なテスト計画を立てるのが常道。


====

あと、引用ではないけどテスト関連で付け加えると、『リファクタリング』に載ってるリファクタリング・パターンのほとんどに「コンパイルしてテストする」と言う手順が組み込まれている事も、改めて確認できる。

この10数年で、リファクタリングという言葉が普及したおかげもあってか、動いてるコードに手を入れる心理的ハードルが昔より低くなったけど、「動いているコードはいじるな」っていう昔からの不文律を乗り越えて良いのは、テストコードという前提あってこそという、基本中の基本が蔑ろにされ始めてるのを感じる。テストもせずにコードをいじって、CIサーバから常時テスト失敗メールが飛んできてるのに何とも思わない連中が、どんどん増えてきている気がする。

出来ている現場の出来てる人達はびっくりするかもしれないけど、まだまだこんな感じの現場が多いんだよな… いかん、また眠れなくなってくる…

0 件のコメント:

コメントを投稿