ユニットテストの網羅性の扱いについて

 テストの網羅性については様々なものがある。基本的な網羅性の観点としては、構造ベース、仕様ベース、外部の標準や指標ベースなどが挙げられる。
 そして観点ごとに、様々な網羅性の指標がある。ユニットテストの場合だと、例えば以下がある。

  1. コードの構造網羅
    • コードの構造を網羅する。ここでいうコードの構造としては、制御フロー、データーフロー、例外フローなどがある。具体的な指標としては、コードカバレッジが有名。コードの構造網羅では、コードカバレッジなどを基準にして、基準以上の網羅性を確保できるようにテストを設計する。
    • なお、構造網羅というと、一般的な定義ではコード以外の構造も扱われるが、このブログでは便宜上「構造網羅をコードの構造を網羅すること」という定義に絞り込んで説明する。
  2. 仕様網羅
    • コードの仕様を網羅する。コードの仕様には、対象(対象の粒度はテストレベルに依存する。例えば関数やクラス、モジュールを単位とする)の外部インターフェースの仕様、ふるまい、(ライブラリ設計などでのコードレベルの)ユースケースなどがある。具体的な指標としては、因子水準の全網羅に対する割合、水準の網羅度などがある。仕様網羅では、対象の仕様をモデル化(原因結果グラフやディジョンテーブルなど、網羅度を計算で来るモデルで記述)し、モデルを網羅するように技法を使ってテスト設計する。

 一応、上記の2つ以外にもいくつかアプローチ(経験ベースや、標準チェック項目の使用など)は存在するが、話がややこしくなるので今回は扱わない。

コードの構造網羅と仕様網羅の使い分け

 このコードの構造網羅と仕様網羅のどちらを重視するかは、テストの目的による。

 例えば仕様が曖昧な状態でのリファクタリングならば、コードの構造網羅が有効だ。そこでは変更前と変更後の両方で高レベル(C6やC7等)のコードカバレッジ100%が得られるテストを設計することで、変更前後でコードの機能的な振る舞いが変化していないかチェックする事が可能になる。

 一方、単体テスト工程などで、仕様未達を網羅的に検出したい場合は、仕様網羅が有効になる。関数やクラスの仕様を満たしているか網羅的に検証することによって、機能的な保障が可能になる上、構造網羅で見逃しがちな未実装バグや冗長な実装を検出できる。

相互の補間

 ただコードの構造網羅、仕様網羅どちらか一方を実施する場合でも、お互いに補間指標として活用することが可能だ。

 例として、仕様網羅でテスト設計を行った場合でも、そのテストで得られるコードの構造網羅の指標(コードカバレッジ等)は仕様やテスト対象の評価に使える。例えばもし仕様網羅のテストで十分なコードカバレッジが得られなかった場合は、仕様に含まれない冗長なコードがテスト対象に存在する可能性が高い。


 また現実問題、完璧な構造網羅が困難だったり、仕様が曖昧で仕様網羅が困難だったりすることが少なくない。そうした問題の緩和にも、コードの構造網羅と仕様網羅の相互補完は有効だ。
 例えばテスト対象が多重ループや小数、状態を扱っていて、十分なコードカバレッジの確保が困難な場合では、仕様網羅を損なわないというルールで、コードカバレッジの基準を安全に下げられる場合がある。
 一方、テスト対象のテスト仕様が曖昧で仕様網羅が困難な場合は、取り合えずコードの構造網羅を進めることで、テスト対象やテスト仕様の気づきを得られることがある。構造を網羅的に分析することで実装の意図も網羅的に読みとれるし、またコードを読むよりテストを読む方が仕様が分かりやすい場面が少なくないからだ。
 さらにあまり良い状態ではないが、仕様の曖昧さ起因でテスト漏れが発生している場合は、コードの構造網羅のテストの追加により、テスト漏れをある程度減らすことも可能だろう。

バグや仕様未達を網羅的に検出するためのテストでの扱い

 ユニットテストの目的でよくあるのが、バグや仕様未達の網羅的な検出だろう。そういったテストは単体テスト工程などでしばしば作成される。そうしたテストにおいてコードの構造網羅と仕様網羅をどう扱うかは、仕様の確保状況に依存する。

 例えば厳格なプロセスを運用しているところに限られるけれど、個々の関数やクラスの入出力が明らかになるまで実装仕様をブレークダウンしているならば、仕様網羅でテスト設計を進めるのが理想になる。コードの構造網羅の指標は、仕様や仕様網羅が妥当かどうか検証する手段になるだろう。

 一方、設計仕様が大まかにしか存在しない場合は、(仕様網羅が理想であるのは変わらないが)コードの構造網羅で、曖昧な仕様網羅をサポートするのが現実的な妥協策になることになる。ただコードの構造網羅を達成しても第一優先である仕様網羅が曖昧なのは変わりないので、仕様網羅を補う対策が別途必要になるだろう。例えば「ライブラリ化を意識してボトムアップで実装仕様を作りこむ」「パッケージやクラス群など大きな構造の実装仕様を確保する」「テスト対象が他のコードでどう使われているか調べてそれを仕様化する」といった対策が必要になってくる。

大事なこと

 仕様網羅、コードの構造網羅で重要なことは、どっちを重視しているか取り違えないことだ。
 例えば前述の「仕様未達を網羅的に検出するためのテスト」では、あくまで仕様網羅が重要だ。そこで構造網羅は補完効果や参考指標として有効なものの、それが完璧だといって仕様網羅をいい加減にすませることはできない。よく問題視されているが、コードカバレッジ100%を達成したからといって、きちんと仕様網羅が達成されているか保証できないからだ。