ふぃーるどのーつ

技術系ブログ「ふぃーるどのーつ」

TDDをめぐる、最近の議論についての私見。

はじめに

DHH氏のTDD is dead. Long live testing. (DHH)のエントリは、国内でもさまざまな議論を呼び起こしました。ですが、そのセンセーショナルな見出しの影響もあり、「(TDDと同一視した上での)ユニットテストは不要」などの、ミスリードされた論調も見られます。乗り遅れた感もあるのですが、前述のエントリに限らず、TDDについて最近考えていることをまとめたいと思います。

TDD=テストファーストではない

ケントベックの「テスト駆動開発入門」や、Uncle BobのTDD三原則の影響もあり、TDDでは、まずテストファーストするのだ、という印象をお持ちの方がいると感じてるのですが、いきなりテストファーストするというのは、教条主義なところがあり、現場に適用するのは敷居が高いのは確かです。

TDDを実践する上で大事なのは、テストによって開発が駆動されることです。すなわち テストコードを書くことと、テストに対になるコード(プロダクションコード)が作業として近い関係にあり、テストコードが、プロダクションコードに対しフィードバックをもたらしてくれることが重要です。なので、「テストコードを先に書く」ことに固執することよりも、まず、どんな形でもいいので、自分の書いたコードに対してテストを書いてみた上で、改善のサイクルを回すのが大事だと思います。

TDDは設計プロセスですが、TraditionalなWebMVCアーキテクチャーの場合、プレゼンテーション層と永続化層の間にレイヤーが押さえつけられているため設計の自由度が低く、設計プロセスとしてのTDDの出番が少ない面はあると、私個人は感じています。そのようなアーキテクチャーの是非はありますが、アーキテクチャーに対し、TDDに限らずどのようなテストで品質をカバーしていくかはプロジェクトごとに検討が必要ですし、全てのプロジェクトの全てのコードに対しTDDが有効というわけではないという点には、私も同意です。

TDD戦略の必要性

これも散見する誤解なのですが、TDDは「全てのコードに対し、1対1でテストを書く」ことを目指していません。 また、プロダクションコード内の各モジュールの粒度に対し、テストの粒度が大きかったり、逆に小さかったりすると、仕様変更や機能追加に耐えられないテストスイートになったり、リファクタリングの妨げになります。

なので、TDDの中で、どこのレイヤーに対しユニットテストを書いて、どこの部分をユニットテストでないテストでカバーするのか、ということをプロジェクトごとに設計する必要があります。

開発者テストと品質保証

TDDは有用なのかそうではないのかという議論を進める上では、TDDは何を目的とするのかという点をはっきりしておく必要があります。まず、原則として、TDDで書かれるテスト(開発者テスト)は、品質保証を目的としません。だからといって、TDDのテストは品質を向上保証しないというのは、それはそれで誤解であり、いわゆる実装(製造)工程と品質保証の工程の関係の理解が不足しているのではないか、と考えます。

重要なのは、開発者テストと品質保証のためのテストはお互いを補完し合う関係にある、ということです。開発者テストでのテストは、開発者の意図を確認するために書かれます。対して品質保証のテストは、ユーザー側の視点から、「ストーリーの受け入れ基準を満たしている」ために行われます(書かれます)。

開発者テストのレベルで「開発者の思ったとおりに動く」ことが保証されているからこそ品質保証のテストは品質の検証に注力でき、品質保証のテストが後詰めとして控えているからこそ、開発者テストはプログラムの中の勘所を押さえることに注力できるのです。この2者間のバランスが崩れていると、品質保証のためのテストでプログラムのカバレッジを意識することになったり、開発者テストとして書くユニットテストの中でシステムとしての品質保証を意識する羽目になります。

そして開発者のテストと品質保証のためのテストに限らず、「テストを書く」ということは、継続的インテグレーションや静的解析、コードレビューやペアプロミングなど、チーム開発のための各種プラクティスと連携して、初めてその力を発揮します。そのことを踏まえずに、TDDだけを取り上げて、開発に役に立つ、役に立たないという論調には、議論としての危うさを感じます。

さいごに

ユニットテストとTDDを同一視してしまう論調に代表されるように、TDDを取り巻く各要素はそれぞれが複層的に折り重なっていて、一つ一つを単独の要素として理解することには困難が伴います。だからこそ、各々の現場の開発プロセスの中で、TDDがどういう位置づけにあるのか、開発プロセスの中でどうやって総合力を発揮するかという点を意識した議論を望みます。