@ledsun blog

無味の味は佳境に入らざればすなわち知れず

TDD の Death and Rebirth まごころを君に

我が輩のTDD体験を語る

背景

ここ最近のTDDに関する話の噛み合なさっぷりよ・・・

大きな疑問

業務でxUnit使ったテストファーストやってる人はいるの?

TDDは死んでないと言うても、業務でxUnit使ったテストファーストやってる人はいるの? じゃあ、自分はどうなのか?自分語りをする。

前提

ここで話すTDD

XPの第一版にはそれ以外の要素は書いてなかった。 俺はそう刷り込まれた。 一番大事だと思う要素から話す。

「これからインスピレーションを得たもっといい方法があるよ」って話は喜んで聞きます。

我が輩の経験

3プロジェクト

  1. C言語のSDPパーサ
  2. C言語のOBEX通信モジュール
  3. C言語ツール

言語の性質は意図してません。たまたま経歴がそうだっただけです。

xUnitを使ったテストファーストの効用

よく言われる通りの効用がある

  • バグが減る
  • 設計が洗練される
  • 設計の練習になる

バグが減る

リリースまでに使う回数が増えるのでバグが減る。 手で動作確認するのに比べると100倍ぐらい多い回数実行できる。 たくさん実行すると、マルチスレッドのデッドロックを体験できることもある。

設計が洗練される

テストクラスはクライアントクラス以外のテスト対象クラスを使う視点になる。 簡易的な仕様変更になる。

下記の仕様に依存している暗黙の前提条件に気付くきっかけになる。

  • 呼び出し順
  • 初期値
  • 入力値の範囲

暗黙の前提条件を減らすと、他のプロジェクトに持って行きやすいポータブルなコードになる。

ただ、この効果は機能追加による現実の仕様変更に劣る。 テストコードは予想外の機能を追加しない。 現実の仕様変更より実践的であることはない。

設計の練習になる

プログラミング初心者の設計の練習によい。

オブジェクト指向入門の4.3 機能的トップダウンアプローチに

機能的トップダウン設計を検討した結果. この手法は重要なソフトウェアシステムの開発には
不向きであることが明らかになった. 小規模のプログラムや独立したアルゴリズムについては
トップダウン設計はなお設計の模範として有用である. また, 系統的に問題を解決できるので, 
初級プログラミングコースの教育法として役に立つことも確かである.

そして

トップダウン法では全てのシステムが最も抽象的なレベルでその第1の機能を記述できるもの
とされている. (中略)現実のシステムには頂点など存在しない。

ともある。

TDDでは

  1. テストコードで第1の機能を指定できる
  2. 機能的トップダウンアプローチが可能
  3. 系統的に問題を解決できる
  4. プログラミング初級者でも処理の設計がしやすい

この性質を利用してTDDの三角測量がなりたつ。

そしてレッド/グリーン/リファクタリングの黄金の回転をまわしながらオブジェクトを見つけ出す。 機能的なアプローチからオブジェクト指向にたどり着ける。

ただし、TDDの三角測量だけでデザインパターンを活用するオブジェクト指向設計にたどりつくのは困難。 慣れてきたらオブジェクト指向のこころを読もう。 (※これは個人の経験に基づく感想であり、効果を保証するものではありません。)

xUnitを使ったテストファーストの前提条件

第1の機能がないと始められない。

事前の設計が必要。 ERモデリングだけでは不十分。 C言語ならモジュール構成。 OO言語なら、クラス単位まで行かないまでもクラス群単位のおおざっぱなオブジェクト構成が必要。 インタフェースの名前と入出力が必要。

三角測量と逆向きになるのでTDD BootCampから実案件への移行には苦労するのではないかと思う。

もうやってない

もう6年やってない。

予算1000万の業務用WEBアプリの場合、オブジェクトの構成が決まらない。 レイヤーはプレゼンテーション、サービス、DAOぐらいで大体固定。 しかし、オブジェクト単位の仕様は画面仕様依存で決まらない。

仮に事前に設計してテストコードを書いても、 画面を見せながら仕様検討・変更する。 機能が変わるとテストコードの修正がコストになる。

画面の機能から作り始めるとユニットテストを書くマインドに切り替えるコストが高すぎる。 それよりユーザのマインドに切り替えた方が以下の良い気付きが得られる。

  • この画面は必要か?
  • 画面のレイアウトから機能が読み取りやすいか?
  • 画面を複数に分けた方がよいか?

画面の機能が8割固まるまでは手で回帰テストを回している。 この時はどの機能がどのプロダクトコードに依存しているか把握している。 どの機能を動かして確認すればよいかわかっているので、 手でやってもそれなりの効率で回帰テストが回せる。

xUnitを使った「後追い自動テスト」はやってる

ある程度機能が固まってから後追いでテストコードを書くことはある。

数年前に作ったライブラリに機能追加するときはテストコードがあるととても心強い。 例えば Alhambra というライブラリのテストはMSTestで書いている。

この手のライブラリをメンテナンスしたい時は、ライブラリのメンテナンスをしたいのではなくライブラリを使用しているプログラムを修正したい。 ライブラリの修正や動作確認に時間を使いたくない。 自動テストがあれば2年ぶりの機能追加でも、テストを実行するだけで既存機能を壊してないとわかる。

ただし、これはxUnitでEnd-to-Endの自動回帰テストを書いている。 実際のデータベースを使って実行している。 ユニットテストとしては悪いと言われているデータベースに依存したテスト。

※これは上記ライブラリの使用を推奨するものではありません。 EntityFrameworkでもLINQtoSQLでも好きなものを使ってください。

自動回帰テスト

作れるならEnd-to-Endの機能テストを自動化した方がうれしい。 テストコードが無駄にならずに内部構成を修正できる。

xUnitレベルのテストではレイヤーの追加・削除やデザインパターンの適用などで オブジェクトの構成を変更すると、かなりのテストコードを捨てたり直したたりすることになる。

結論

「xUnit使ったテストファースト」は死んだ。

あとは知らん

参考文献

XPエクストリーム・プログラミング入門―ソフトウェア開発の究極の手法オブジェクト指向入門オブジェクト指向のこころ