現場のテストコードはどこへ?

あまり聞かないテストコード

ここでいうテストコードとは、例えば JUnit を利用したテスト。気軽にコードを動かすことができ、細かいところのテストができる。なんといってもその後の修正に対するデグレ防止にもなる。

そんな便利なものではありますが、これをうまく活用してシステム開発・運用をしている現場は、あまり見かけません。少なくとも jflute の経験上。また、他の人にもこの話題をよくふりますが、「うーん、ちょっと書いてるけどね」「いままでまったく見たことないです」答えは様々ですが、少なくとも活用されている現場の話は「多く」は聞こえてきません。

テストコードのコスト

そこに常にあるテーマとして...
「テストコードをたくさん書くと仕様変更時の修正コストが高い」

もう一つ大事で根本的なテーマ...
「そもそもテストコードを書くコストが高い」

どちらも無視できない大きな「足かせ」です。特にリーン・スタートアップ、インクリメンタル開発なサービス開発では、前者のコストは大きくのしかかります。

運用のしやすさ加減

まず大前提を自分の経験則から。うまく活用している現場と、していない現場では、結合テストのときの「火の吹かなさ加減」と、その後の「運用のしやすさ加減」が格段に違います。

特に運用後の変更に対するスピードが大きく異なります。結局、作ってからの変更って、とにかくデグレが怖いんですね。だから、それなりのテストをしないといけないのですが、現実的にはテストする時間があまりないでしょう。リスクを背負って前に進むわけですが、つまづくこともあるでしょう。自動テスト実行で全てをまかなえるわけではありませんが、それでも多くの確認作業を省くことができます。

まあ、あんまり変更のない業務なら別にいいかって感じですが、最近「変更のない業務」ってあまり少ないように思えます。

ただ、変更の多い業務でテストコードを書きすぎると、修正コストが高い、という矛盾も常にそばに存在します。

ここでいう「うまく活用している現場」とは、先ほどの「テーマ」をクリアしている場合に限るでしょう。手強いテーマです。

小さなブラックボックス

自分が主導したプロジェクトで実際にやってみたアプローチは...

o カバレッジは100%を目指さない。(カバレッジはしょぼい)
o 定型的なテストしか書かない。(サンプルを徹底して作る)
o このプロジェクトに合ったテストコードを書く土台を作った

共通部品は、それなりに書きます。共通部品を作る人は、テストコードを書くのにもなれているのでスピードも出ます。共通部品がバグっていると、プログラマデバッグスピードは極端に下がります。なので共通部品はしっかり堅く。

画面は、リクエストを受け付けるエントリポイントのメソッド、PageクラスやActionクラスのpublicメソッドたち、これらを叩くテストしか書きませんでした。単にクラスを new して、そのメソッドを叩く、それだけ。その結果、クラスの状態(リスポンスの関わる変数たち)が、どのようになっているかをアサート。細かすぎないこと。

エントリポイントから、DBまで一気通貫で動作させます。テストデータはきっちりと揃えます(ここ重要、大変だけど)。アサートは計算ではなく、ベタに期待値をハードコード。これをやるにはデータは綺麗にしていないと。単体テストって感じよりかは、クラス結合テストって感じかな。

定型的なテストだけに絞る。そして、モックは使わず、データさえ整備されていれば書けるテストに注力。そういったテストを書くための土台もしっかり整備。テストのためのユーティリティを多く準備。そのプロジェクト専用のメソッドとかなどなど。

「これだけは書いて!」

という感じで、プログラマに横展開して実装してもらって、先ほどの「テーマ」が重くのしかかるようなことはあまりなく、そのメリットをいい感じで享受できように思います。

これは単なる一つの状況に対する一つのアプローチ。これが正解でもないし、ただ結果的には悪くもなかった。

テストコードの自主練は?

土台が整ってない、そのプロジェクトのテストポリシーが定まってない。これらは確実に足かせにはなります。テストコードを書くのに慣れてても、これがなければやはり書きづらい。そこはアーキテクトが色々考えないと。

ただ、結局は、一番左右されるポイントがここ。

「多くのプログラマがテストコードを書くのに慣れていない」

テストコードを書くのが遅いだけでなく、「書きすぎない」のさじ加減が判断できないから。

メインのコードが書けなければ、教育コストもかけるし、本人も勉強してプログラムが書けるように頑張る。ただテストコードが書けなくても、そこに教育コストをかけることはあまりない。プログラマ本人も「今日は家に帰ってテストコードを書く練習をしよう」という人はあまりいないんじゃないかと。

なかなか現実的に、業務でテストコードをすらっと書けるプログラマが集まることはないのかなと感じています。結局、ここが足かせになるし、とても流動的なので、現実解を見つけるのがとても難しくなる要因になるのかなと。

現場の様々な状況を加味した上で、いかに少ないコストで多くの利を得るか、

常にここは悩ましい部分...うーん

【追記: 2013年頃】
ここ最近は、「画面から叩くにはケース的に難しいロジック」それだけをちょこっと動作確認するために、JUnit単体テストで書く、っていうやり方をアドバイスしています。それがやりやすいようにするための、UTFluteというJUnitの拡張モジュールも提供。
 => UTFlute | DBFlute

単体テストを「建設的に」利用しつつも、逆にそうやってハードルを下げて、まずは慣れ親しんでもらうようにと。また、リーン・スタートアップの開発では、それが限界とも言えるかもしれません。

あと、DBFluteハンズオンでは、エクササイズを単体テスト形式でやって、DBFlute学びつつ自然とテストコード実装も学べるように、っていう風になるように。jflute流の一つのアプローチです。

// 思考力DBFluteハンズオン
http://d.hatena.ne.jp/jflute/20130602/1370192962

【追記: 2014年頃】
さらには、
「費用対効果の高い横断的なテスト」
を現場で推し進めています。

例えば...
o DIできないフィールド宣言が存在しないこと
o formタグのaction属性に対応するするActionがあること
o そのプロジェクトで使わないと決めた機能やメソッドを使ってないこと

などなど。

プロジェクト独自ルールのチェックスタイルみたいな感じですね。それを UTFlute の PoliceStory を使って単体テストで書きます。
 => UTFluteでいろいろ

こういうテストであれば、わりと効果が高いので導入しやすいかと。もう少し業務よりなロジックで書けるようになったらさらにいいかなと。現場のプログラマーは喜んでくれていますし、jfluteが書いた土台を元に、新たなテストコードを書いてくれています。(ありがとう、ありがとう)