『単体テストの考え方/使い方』を読んで現実的なテスト駆動エンプラ開発を考えよう
年末年始に『単体テストの考え方/使い方』(原著: Unit Testing Principles, Practices, and Patterns, 以下 UTPPP) を読んだ。
UTPPP 内でも紹介されているが、テスト駆動開発 (TDD) には大きく「デトロイト学派1」と称される考え方と「ロンドン学派」と呼ばれる考え方が存在して、その最も大きな違いはモック (テスト・ダブル) に対する考え方にある。自動化されたテストによるアプリケーションのテストカバレッジを向上させる上でテスト・ダブルの活用は避けて通れないが、テスト・ダブルの利用にはメリットもデメリットもあるため、2つの学派のスタンスを踏まえた上での落とし所を見つけることが重要となる。
テスト駆動開発にはざっくりいうとモックを積極的に使う派(ロンドン学派)とあまり使わない派(デトロイト学派、古典派)がありまして、私は後者なのでほとんど使わず、このエントリに深く同意するところです / “モックは必要悪で、しないにこしたことはない - …” https://t.co/VjDvospTKu
— Takuto Wada (@t_wada) 2021年10月15日
デトロイト学派のバックグラウンドとなる書籍として有名なものが Kent Beck による『テスト駆動開発』(通称: TDD本) であり、一方でロンドン学派による TDD 手法が解説されているのが『実践テスト駆動開発』(通称: GOOS) である。JUnit を始めとする "xUnit" と称されるテスティングフレームワーク群を用いたテスト手法パターンを解説した『xUnit Test Patterns』(通称: xUTP) もバイブルとして挙げられるだろう。UTPPP では、この3冊の内容を踏まえた上で、現実的なエンタープライズアプリケーションにおける自動テストの実践方法が説かれている。 TDD本やGOOSが単体テストを通じた「真っ当なオブジェクト指向プログラミング」へと導いてくれるように、UTPPP も書籍を通してテスタブルなアプリケーションアーキテクチャを実現してゆく過程で ヘキサゴナル・アーキテクチャへと行き着く流れがよく出来ていると感じた。
極めて個人的な視点で、そんなUTPPPの推しポイントを2点紹介してみたい。
エンハンスし続けるアプリケーションの目線からみたテストの価値観
「良い単体テストとはどのようなものか?」という問いに対するよく聞く回答の一つに「良い単体テストは F.I.R.S.T. の原則を満たす」と言われる。
- Fast: 高速に実行される
- Isolated / Independent: 他のテストケースや依存先から隔離され、独立している
- Repeatable: 繰り返し実行できる
- Slef-validating: テストの成功・失敗を単体テスト自身が判断できる
- Thorough: 網羅性がある2
この F.I.R.S.T. の原則は間違いなく重要だし、効果的な単体テストを書くスキルを身につけるための出発点であることは間違いない。一方で、F.I.R.S.T. には「プロダクションで動くアプリケーションをメンテナンスし続ける」ために必要なバランスという視点が欠けているようにも思える。『Googleのソフトウェアエンジニアリング』にて「エンジニアリングとは、プログラミングを時間方向に積分したもの」という言葉があるが、F.I.R.S.T はまさにプログラミングの視点で「テストを書く」ための指針なのである。
そこで参考になるのが、UTPPPの示す「良い単体テストを構成する4本の柱」だ。これはまさに単体テストの「エンジニアリング的」な価値基準を表しているのではないだろうか。それぞれの詳しい解説は本書に譲るが、具体的には、以下の4つである。
UTPPP の中ではこの4本の柱の中でも「保守のしやすさ」以外の3つはトレードオフの関係にあると述べている。1つめの「リグレッションに対する保護」はテストの存在意義そのものであるためトレードオフ上捨てるという選択は存在しない。どのように残りの「リファクタリングへの耐性」と「迅速なフィードバック」のバランスを取り、テスト・ピラミッドを構成してゆくのかを考えることが本書のテーマだ。だから「単体テスト」と題名に冠されているが、最終的にはインテグレーションテストまでを扱うことになっている。
モックの使いどころの理路整然とした解説
これまで自分自身も、サーバーサイドアプリケーションを開発する上でさまざまなテスト・ダブルを活用してきた。「この場面ではXXXをモック化するべきか、実態を利用するべきか」は常にチーム内で議論になるものだし、言語化も難しいテーマだ。なんだかんだ開発がスムーズに進む場所で落ち着きはするのだが、もう少しロジカルな納得が欲しいと思っていた。
UTPPPでは、依存関係を「共有依存」と「プライベート依存」、「プロセス外依存」などの分類をしながら、どの依存関係にテスト・ダブルを導入するべきかを説いているところが良い。自動テストのピラミッド理論を知っていたとしても、そのピラミッドを体現するための匙加減や技術的なコツをしっかりと言語化した資料にはなかなか出会えないのではないだろうか。
言うなれば、UTPP はテストに関する経験値稼ぎのショートカットになるのではないかと思う。これまで「ちょうどよいテストピラミッドを構成するための勘所はメンターと仕事を共にして養おう」となっていたものが、そのようなメンターに恵まれなくてもなんとか試行錯誤をする勇気をくれるのではないかと思っている。
各論でいえば「そうは書かないだろう」と思う部分もあるし、C#というプログラミング言語に疎いが故に持つ違和感もあるのだが、全体的にはとても良く整理されている書籍だと思いました。気になる方はぜひ。