結論
コードカバレッジでは、テストが十分であることを証明できません。また、「コードカバレッジ100%を達成」だけを目的にすると様々な問題が起こります。コードカバレッジは、あくまでもソフトウェアの健康状態を測る指標の1つであると認識し、その1つとして活用してください。
コードカバレッジに囚われて、私達が本来目指したかったはずの次の目的を忘れないでください。
・本番環境で見つかるようなバグは、発生していない状態
・本番でバグが発生することを恐れてコードの変更を躊躇することがない状態
逆にいうと、これらが達成できていれば、例えカバレッジが低くともテストコードを十分に書けているといえるでしょう。
目的を忘れずに、テストを改善していくことで次第とコードカバレッジも高くなっていくでしょう。
「コードカバレッジ100%の達成」を目指してはだめな理由
様々な理由があるのでいくつか紹介します。
「コードカバレッジ100%を達成」を目指すと弊害が起こりうる
コードカバレッジを100%を目指すと、「コードカバレッジの100%の達成」が目的になってしまいます。手段を目的にするのは、悪いことではありませんが、コードカバレッジの文脈においては、「コードカバレッジの100%の達成」を目的にしてしまうのは明らかに悪いことです。
メタファー
病院にいる患者さんを思い浮かべてみてください。体温が高いということは、熱があるということであり、状況の把握には役立ちます。しかし、この患者さんの体温が適正であることを、何が何でも目指すべきではありません。目指した場合、患者さんの隣にエアコンを設置し、肌に当たる冷気の量を調整することで体温を調整するという、手っ取り早くて意味のない効率的な解決策を取ってしまうかもしれません。
カバレッジの偽装
カバレッジは簡単に偽装できます。
例えば、次の例では、ステートメントカバレッジは、4/5で80%です。
public static bool IsStringLong(string input)
{ 1
if (input.Length > 5) 1
return true; 2
return false; 1
} 1
public void Test()
{
bool result = IsStringLong("abc");
Assert.Equal(false, result);
}
3項演算子を使うと、ステートメントカバレッジを、1/1の100%にすることができます。
public static bool IsStringLong(string input)
{
return input.Length > 5 ? true : false;
}
public void Test()
{
bool result = IsStringLong("abc");
Assert.Equal(false, result);
}
※ブランチカバレッジを用いた場合、この場合の偽装はできません。
アサーションフリー
アサーションがない状態でも、カバレッジを100%を達成することができます。
例えば、次のコードでブランチカバレッジを100%にすることができます。
public void Test()
{
bool result1 = IsStringLong("abc"); 1
bool result2 = IsStringLong("abcdef"); 2
}
本来は、期待している通りに動いているのかを確認したいです。アサーションがない状態では、実行が途中で終わらないことのみの確認しかできません。つまり実行時エラーが起こらないことのみ確認できます。
もし、Null Pointer Exceptionなどの欠陥がある場合は、それを見つけることができます。
カバレッジ100%でもライブラリについては担保できません
次のコードの例では、カバレッジは100%担っていますが、nullをinputとして渡したときや
""をいれたときや、"int型でない文字列"の動作については確認できていません。
public static int Parse(string input)
{
return int.Parse(input);
}
public void Test()
{
int result = Parse("5");
Assert.Equal(5, result);
}
ユーザの期待に応えられているかを示すことはできません
コードを100%カバーしていることはわかりますが、ユーザを満足させているかは不明です。
例えば、次のような期待に答えられていない可能性があります。
・ユーザーが使いづらいと感じるワークフローがある。
・ユーザーが期待する情報が含まれていない。
・安全性に問題がある、または十分な安全性がない。
・ユーザーが必要とする機能が欠けている。
・メモリリークが発生し、一定時間後にクラッシュしてしまう。
表示上の問題を防ぐことはできません
ユーザの画面サイズが期待したものと違っていたり、ユーザーが使用したフォントや同じエンコーディングを使用していないシステムでアプリケーションを実行したりすると、表示上の問題に遭遇することがあります。これらの問題は、ユニットテストや統合テスト、自動化された機能テストでは検出されないものです。
まとめ
結論はこちらに書きました。
個人的に理解できたものについてまとめ直しました。
インテグレーションテストやAPIテストやE2Eテストもあるので、コードカバレッジで証明できる範囲も広がっている気がしますが、それを考慮できていない気がするのが今のもやりポイントです。
ご参考になれば幸いです。
参考文献
こちらの文献を参考にさせていただきました。
Vladimir Khorikov. Unit Testing Principles, Practices and Patterns : Manning Publications