何をもって「単体テストが完全である」とするか?

xUnitでの単体テストは半ば常識化してきていますが、
何をもって単体テストが完全なものかを判断するのは非常に難しいものがあります。

例えば、「カバレッジ(C0,C1)を100%にする」と言う前提でテストを作成しても、テストは足りない事が殆どです。
限界値では異常な値を返すような場合はこれでは100%見付けることが出来ません。
ちなみにカバレッジ測定(Java)ならDjUnitがありますので、是非活用を。

やはり、限界値を考慮した上でのカバレッジ100%がよいのでしょうか?
いえ、まだ足りません。
カバレッジは組合せまでは見ていないためです。
例えば、3つの状態を組み合わせて値を返すようなものであれば、
カバレッジを100%にする場合、3つ状態が全て真の場合と全て偽の場合の2パターン用意すれば100%になっていしまいます。
が、実際のところ組合せなので、6通りのテストが必要となります。(たぶん)

組合せを考慮した上でのテストが出来てこれで完璧かというとそんなことはありません。ここで50%程度でしょう。

私も面倒で作らないことがありますが(笑
故意に失敗するテストも必要です。
失敗が、きちんと捕捉され、正しい例外が起こるかどうかや、
失敗を失敗として計算結果を返すようになっているかをテストしてあげる必要があります。
ここが一番カバーしにくい部分であり、
感覚を養うまで非常に苦労する部分でしょう。

つきなみですが、
public int div(int a, int b) {
  return a / b;
}
というコードがある場合、0除算が発生した場合の考慮がまったくされていません。
システム的にありえないとしても、
なにかしらの記述が必要でしょう。

その1 システム的にありえない場合
Javadocにその旨を明記する。
/**
* 割算
* <pre>0除算は××システムでは起きない前提なので考慮していない</pre>
* @param a 分子
* @param b 分母
* @return 割算の結果
*/
など。

その2 システム的にありえない場合
契約による設計を用いる
public int div(int a, int b) {
  assert 0 != b;
  return a / b;
}
など。

その3 システム的にありえる、かつその答えがある場合
public int div(int a, int b) {
  if (0 == b) {
    // 分母が0の場合、答えは0になる。
    return 0;
  }
  return a / b;
}
など。
これはJavadocにも明記すべきでしょう。

このようになってくると、失敗(値が不正)に対しての考慮も必要です。
このあたりを考慮に入れ、完璧にちかいテストを作成するように心がけましょう。(私も含め)

それと、カバレッジ100%は必ずしも守らなければならないものでは無く、目安として使った方が良いです。
getterやsetterそれに近いメソッドをテストする意味は殆どありません。
他のテストを行う際に、それらを使いテストを行うとかが出来れば良いですが。
entity等はそれしかないので、テスト対象外とするのは良いとして、
そのあたりを考慮し、100%を目指すが、例外は認める。
が妥当なところでしょう。
後者の場合、レポートが自動で出力されるような場合、意図的に100%ではないのかを判断することが難しいので、やり方を工夫しないと破綻する場合があるでしょう。

以上 長くなりました。
ついでですが、明日から実家に帰省します。
その間ブログは放置プレイになりますので、予め御了承ください。