はじめに
テストコードを書く際に、
テスト対象のどこに対して検証すべきか??
について本(単体テストの考え方/使い方)を読んだり、
現場でテストコードを書いたり、テストコードや設計の改善を行ってきた自分の体験
を基にまとめてみました。
テスト対象に対してテキトーに検証していると
テストコードが、
リファクタリング時に結果は正しいのに嘘の警告をするようになります。
それが頻発すると、
最悪開発者がテストコードを無視するようになり、
テストコードの価値も無くなります。
そうならないように、
テストコードを書くときの一つの注意事項として、
抑えておくといいと思いこの記事をまとめました。
実装の詳細を検証するとリファクタリングへの耐性がなくなる??
テストコードにはテスト対象の多くのコードを実行でき
退行に対する保護を備えるだけでは、
価値の高いテストコードとは言えません。
リファクタリングへの耐性も備える必要があります。
詳細については以下の記事をご覧ください。

では、
リファクタリングへの耐性が低くなる原因は何でしょうか??
テストコードがプロダクションコードとより密接に結びつくと、
リファクタリングへの耐性はより低くなります。
シンプルな単体テストコードの例ですが、
テスト対象の処理途中の過程を検証すると、
リファクタリングへの耐性は低くなります。
例えば、リファクタリングで処理4をなくせた、
もしくは処理4を処理5とまとめた場合、
最終結果が変わらず正しいのにテストコードは
途中経過の検証部分でNGになります。
(偽陽性が増えてしまう)
自分自身、
このようなテストコードが量産されている現場で
リファクタリングをしたことがあります。
せっかくテストコードに退行に対する保護が備わっていても、
リファクタリングへの耐性が低いせいで、
そのテストコードは常にリファクタリング時に修正が必要となり、
必要以上にリファクタリングに工数がかかるようになったり、
一部の開発者はテストコードを無視してソースコードをマージしたりと・・・
テストコードが機能しなくなっていきました。
では先ほどの例の場合どのようにテストコードを修正すれば良いでしょうか??
テストコードをテスト対象の内部的なコードから切り離すことが重要です。
そのためにはテストコードでの検証を、
テスト対象が実行した最終結果のみにする必要があります。
つまり、検証する対象を観察可能な振る舞いのみとし、
最終結果のための細かい手順である実装の詳細には目を向けないようにするのです。
テスト対象のコードを呼び出す側の視点で検証し、
呼び出す側にとって意味のある実行結果のみを確認し、
その他のことに関しては何も検証していません。
それ以上検証するということは、
テスト対象の実装の詳細に踏み込むことになり、
その結果、必要以上に検証してリファクタリングへの耐性の低い
テストコードにつながってしまいます。
何も考えずにいろんな箇所を検証して
assertion書きまくったり、
工数をかけて退行に対する保護をしようとすると、
実はリファクタリングへの耐性をテストコードが失っている
というケースは現場ではよくある印象です。
気をつけましょう!!
今回の例は非常にシンプルな単体テストコードをイメージしたものでしたが、
統合テストで副作用やプロセス外依存を扱うような場合はそう簡単にはいきません。
その辺りについてはまた別の記事でまとめようと思います。
ただ、テストコードにリファクタリングへの耐性を持たせるための
考え方の基本は同じかと思います。
プロジェクトが進むほどリファクタリングへの耐性がより重要
プロジェクトの初期段階(新規開発が始まった段階)
ではリファクタリングの必要がそこまでないため、
退行に対する保護にだけ注意しておけば問題にならないケースもあります。
しかし、
開発したシステムがリリースされ、
保守開発フェーズに入り、
時間が経つにつれてコードが劣化してくると
リファクタリングによる整理が必要になります。
ここでもし、
テストコードにリファクタリングへの耐性がなければ、
問題になります。
自分も保守開発フェーズで、
リファクタリングへの耐性を備えていないテストコードのせいで、
テストコードの改善が必要になったプロジェクトの現場を体験しましたが、
多くの開発者は退行に対する保護や偽陰性(警告されないバグ)の方に目がいきがちで、
リファクタリングへの耐性はおろそかになりがちです。
そもそも、リリースをゴールと捉え、
その先の保守開発フェーズ以降の成長を意識しない開発。
システムの難易度やプロジェクトの規模的にリファクタリングが不要な開発。
など原因はいくつか挙げられますが、
テストコードにはリファクタリングへの耐性を備えさせる必要がある。
備えさせられなければ保守開発フェーズ以降必要以上に工数がかかる。
リファクタリングへの耐性を備えさせるために実装の詳細を検証すべきでない。
この辺りを意識してテストコードを書くことが、
価値の高いテストコードを作ることに繋がると思います。