「単体テストの考え方・使い方」を読んだ

単体テストの考え方・使い方を読んだので、印象に残った箇所のメモ

テストコードも含めたコードは、最小限にするべきである

「第1章 なぜ、単体(unit)テストを行うのか」に以下のような記述があります。

 開発者の中には、プロダクションコードとテストコードは別物だと思っている人が多くいます。そのような開発者はテスト・コードのことをプロダクションコードのおまけとしてみており、所有してもコストはかからないと考える傾向があります。 さらには、テスト・ケースは多いほどよいと思っている開発者も多く存在します。 しかしながら、その考えは間違いです。 なぜなら、コードは資産ではなく負債だからです。 つまり、コードが増えれば、ソフトウェアにバグが持ち込まれる経路が増えることとなり、プロジェクトを維持するコストも高くなってしまう、ということです。

 そのため、この問題を解決するためには、コードは最小限にするべきなのです。 そして、ここで言うコードには、テスト・コードも含まれます。

1.2 なぜ、単体テストを行うのか? Column プロダクション・コードとテスト・コードの関係

これまでテストケースは網羅率が高ければ高いほどよい、という価値観を持っていたので、「テストコードも含めたコードは、最小限にすべきである」という主張には学びがありました。

では、どのようなテストケースが不要なのか。 この具体例が「第10章 データベースに対するテスト」にありました。

 このように、書き込みの機能をテストすることは非常に価値のあることであり、このテストを行うことで書き込みの間違いを防ぐ保護を得られるようになります。

 しかしながら、読み込みの機能の場合は違います。仮に読み込みの機能にバグが含まれていたとしても、通常、大きな外をもたらすことはありません。そのため、読み込みに対するテストは書き込みに対するテストよりも重要度が低いことになります。このことから、読み込みに対するテストをするのであれば、その読み込みが非常に複雑な場合、もしくは、重要な役割を担う場合だけにすべきです。一方、そうでない読み込みであれば、無視をしても構いません。

10.5.1 読み込みに対してテストをするべきか?

 リポジトリには、それほど複雑なコードが含まれることはありません。 そして、リポジトリを検証することで得られる退行に対する保護は、通常の結合テストをすることで得られる保護と多くの部分が重なります。 そのため、リポジトリをテストしたとしても、それによって新たな価値がもたらされることはありません。 もし、リポジトリに複雑さが含まれていて、テストをする必要があるのであれば、その複雑さをもっとも効果的に行う方法は、その複雑さを自己完結型アルゴリズムとして抽出し、そのアルゴリズムだけを検証の対象とすることです。

10.5.2 リポジトリをテストすべきか?

これまで、プロダクションコードがあればそれに対するテストコードを書く、という行為をよく考えず当然のことのように行っていましたが、本当にそのテストケースに価値があるのかを検討し、場合によってはテストコードを書かない、という判断をすることの必要性に気付かされました。

古典学派とロンドン学派

本書を読んで、単体テストには古典学派とロンドン学派という2大派閥があることを知りました。 古典学派とロンドン学派は「第2章 単体テストとはなにか」で登場します。

 古典学派はデトロイト学派とも呼ばれ、もっとも古典主義的な方法で単体テストに取り組む学派です。Kent Beck氏によって執筆された「Test-Driven Development: By Example」は古典学派にとって聖典と言えるでしょう。

 一方、ロンドン学派の人たちのことをモック主義者(mockist)と呼ぶこともあります。このロンドン学はの中でもっとも著名な提唱者はSteve Freeman氏とNat Pryce氏でしょう。彼らが書いた「Growing Object-Oriented Software, Guided by Tests」はこの題材を学ぶ教材として一度読むことをお勧めします。

2.1 単体テストの定義 Column 単体テストにおける古典学派とロンドン学派

単体テストには2つの派閥があることはわかりましたが、では、どちらの派閥の考えを採用すればよいのか。 これについて「第2章 単体テストとはなにか」に以下の記述があり、本書は古典学派の立場をとっていることがわかります。

 しかしながら、この2つの学派の違いで最も重要なのが、単体テストはプロダクション・コードのことをどのくらい把握しなくてはならないのか、ということです。 言い換えると、テスト対象の内部的なコードとどれくらい結びつくのか、ということになります。 一般的に、ロンドン学派のほうが古典学派よりも実装の詳細に深く結びつく傾向があります。 そして、このことがモックの幅広い利用や一般的なロンドン学派のスタイルに私が賛同できない最大の理由になります。

2.3.4 その他の古典学派とロンドン学派の違い

それぞれの派閥で単体テストの捉え方が違うため、良しとされるテストコードの書き方にも違いがあります。 そのため、単体テストについての情報収集をする際には、どちらの学派をベースにしているのか、を意識しないと情報が錯綜してしまい、混乱してしまいそうですね。 また、チーム開発する際は、単体テストに対する認識をチームであわせておくことも重要だと思いました。

モックの使い方

これまでの経験からモックに対する考え方は人それぞれだなと思っていましが、本書「第5章 モックの利用とテストの壊れやすさ」にも以下の記述があり、モックは物議を醸すトピックであることがわかります。

 テストにおいて、モックの利用は物議を醸すトピックです。 モックが以下に優れたツールであり、作成するほぼすべてのテストケースにモックを導入するべきだと考える開発者がいる一方、モックはテストを壊れやすくする傾向があるため、できるだけモックを使わないで済むようにするべきだと考える開発者もいるからです。

第5章 モックの利用とテストの壊れやすさ

私はモックの使い方について、テストが壊れやすくなるため極力使いたくない、という価値観を持っていました。 ただ、この極力がどの程度なのかはなんとなくの感覚で判断していただけで、モックを使う・使わない基準についてはっきりと言語化はできていませんでした。 これについて、本書「第9章 モックのベストプラクティス」で言及があり、なんとなく感覚で判断していたことが整理できました。

・モックを適応するのは管理下にない依存にのみにする。

・そのような依存とのコミュニケーションを検証する際、モックの置き換え対象とするのはシステム境界に位置するものにする。

・モックの利用は結合テストに限定する(単体テストでは使わない)。

・モックに対して行われた呼び出し回数を常に確認する。

・モックの対象となる型は自身のプロジェクトが所有する型のみにする。

9.2 モックのベストプラクティス