テストの規律

 TDDを人に薦められるほど修練が進んでいない身だけれども、TDDに関することでモヤモヤと感じていることをまとめてみる。


 とりあえず世間一般では、TDDのテスト≠ドキュメントという意見を時々見る。
 今回はそれに関するものだけれど、ドキュメントにしにくい一部のテストの存在を理由にして、なし崩し的にドキュメントにならないと割り切るのは損をしていると感じる。

 周知の通り、テストは大きな力を持っていて、TDD以外にもリファクタリングやモジュールのバリデーションの道具として使えるし、デバッグでも問題の絞込みに便利だ(これに関しては、TDDを実践していればバグの原因は自明になるなんて意見もあるけれど)。
 ただ全てのテストがそのように使えるというわけではなくて、やっぱり「コードのリファクタリングをやりやすく」といった目的があれば、それに適しているかという評価軸で、テストコードに優劣が出てくる。

 そうした環境において、優れたテストを作っていくには、テストに規律が必要になると感じる。たとえTDDであっても。

 もちろんその規律はMISRA-Cのようなガチガチに運用基準が固められたものではなくて、例えば粗雑に仕様や用例のテストを済ませる方法と、document-likeなテストで記述できる方法、どちらを選んでも問題ないという状況なら積極的に後者を選び、また例えばテストコードのリファクタリングがしにくいテストの記述と、リファクタリングしやすいテストの記述、どちらを選んでも問題ないという状況では積極的に後者を選ぶ、といったもの、をイメージしている。


 規律の例としては、例えばテストコードの再利用性を重視するなら、BDD(ビヘイビア駆動開発)やEDD(Example Driven Development。イグザンプルドリブン/用例駆動開発)のアプローチが有効だと思う。
 すなわち、
・モジュールの仕様としてテストを設計する
・モジュールの用例としてテストを設計する
というもの。例えば、雑多なテストで総合的なユニットテストを構成するより、ストーリーテスト(given[この条件で]→when[これが発生すると]→then[この結果が返ってくる])のような形を意識してテストを組立てていく…ことをたとえ守れなくても意識する。そこでは効率重視により生まれた雑多なテストコードを、この規律に近づけるように後からリファクタリングするのも有効な選択肢になるかもしれない。
 こういうアプローチは、現状TDDで定番なxUnit等によるユニットテストのレベルでも、十分に実現できると感じる(というよりCSpecなどのBDD/EDDフレームワークと比べて構文の最適化度が低い分、より後付の規律と親和性に優れているかもしれない)。


 とりあえず、テストは制約(H.W.依存部のテストが難しい、privateで隠蔽されている、等)が大きい分、やり方の自由度を多めに見てもらっている印象を受ける。そうした状況では、規律のようなものがテストを書く作業の効率に大きく響いてくると思う。