なぜ高いコードカバレッジは何の価値もないと間違った結論にのみつながる


コードカバレッジは、アプリケーションがテストフレームワークによって実行されるパーセンテージの度合いを示します.これは、品質保証とソフトウェアの品質を向上させる“ヘルプ”に使用されます.
この記事では、なぜ私はコードカバレッジの品質を向上させることはありませんが、偽造することができますし、何をすることができます品質を確保するために行うことができます.
ほとんどのツールでは、実行されるコード行のコード範囲の割合が表示されます.通常、ユニット、インテグレーション、エンドツーエンドのテストはカバレッジを増加させるのに役立ちます.これは、コードによってテストされたコードを取得するためのテストを書く必要があるということです.しかし、それは本当に唯一の方法ですか?それが本当にCの例であるならば、見ましょう.
namespace ConsoleApp1
{
    public class SimpleClass
    {
        public string SimpleProperty
        {
            get;
            set;
        }

        public string SimpleMethod(bool value)
        {
            return value ? "simple yes" : "simple no";
        }

        public int SimpleMethod2(string value)
        {
            return value.Length;
        }

        public bool SimpleMethod3()
        {
            return true;
        }
    }
}
私は基本的なことを行うプロパティと3つのメソッドを持つ小さなクラスを作成しました.テストがこのようなクラスのために書かれるとき、それは以下のコードに似ているかもしれません.
[Test]
public void Test1()
{
   SimpleClass simpleClass = new SimpleClass();
   string value = simpleClass.SimpleMethod(true);
   Assert.IsTrue(value == "simple yes");
}
この単純なテストは1つのメソッドを実行し、出力をアサートします.
テスト1のコードカバレッジ
クラスを「テスト」するより複雑な方法がありますが、このコードが自動的に他のクラスを「テスト」することを意味するメソッドの実行を自動化します.コードは非常に基本的な例です.それは私のポイントを表示するために役立つ必要があります.
[Test]
public void Test2()
{
    Assembly assembly = Assembly.Load("ClassLibrary1");
    Type[] objectTypes = assembly.GetTypes();

    var parameterInstances = new Dictionary<Type, List<object>>();

    foreach (Type objectType in objectTypes)
    {
        if (objectType.IsClass)
        {
            ConstructorInfo objectConstructor = objectType.GetConstructor(Type.EmptyTypes);
            object objectInstance = objectConstructor.Invoke(new object[] { });

            var methodInfos = objectType.GetMethods();
            foreach (var methodInfo in methodInfos)
            {
                var parameterInfos = methodInfo.GetParameters();
                var methodParameters = new List<List<object>>();
                for (int i = 0; i < parameterInfos.Length; i++)
                {
                    Type parameterType = parameterInfos[i].ParameterType;
                    if (!parameterInstances.ContainsKey(parameterType))
                    {
                        if (parameterType.IsValueType)
                        {
                            parameterInstances.Add(parameterType, CreateValPossibilities(parameterType));
                        }
                        else
                        {
                            parameterInstances.Add(parameterType, CreateRefPossibilities(parameterType));
                        }
                    }
                    methodParameters.Add(parameterInstances[parameterType]);
                }

                List<List<object>> parameterPermutations = GetAllPossibleCombinations(methodParameters);
                foreach (var parameterPermutation in parameterPermutations)
                {
                    methodInfo.Invoke(objectInstance, parameterPermutation.ToArray());
                }
            }
        }
    }
}
このコードが何かを説明するにはreflections :
  • 「ClassLibrary 1」アセンブリを読み込み、含まれるすべての型を収集します
  • 型コレクションを反復処理し、クラスであるもののインスタンスを作成する
  • このクラスのメソッドを反復処理し、特定の型の特定の値を持つパラメーターを作成し、それらのメソッドを実行するためのメソッドを渡しますFuzzer )
  • SimpleClassのコードカバレッジを推測します.
    Test 2のコードカバレッジ
    このコードサンプルは、単純にカバーできない枝があるので、他のシナリオですべてのコード行を実行できません.確かに、ラインカバレッジのいくつかの高い程度を持ってコードを調整することができますが、これは品質を向上させません.理論によって、我々は今、このkpiを読むとき、「品質」を成し遂げました.実際のコンテキストを実行せずに実行するコードを実行すると、何の意味もありません.しかし、あなたは代わりに何を努力すべきですか?
    コンテキスト!我々は環境、ユーザー、入力とプロセスについて知っている文脈を必要とします.説明するために、なぜコンテキストを必要とするのか、SimpleClassで例題を作り、SimpleMethod 2を見てみましょう.
    public int SimpleMethod2(string value)
    {
        return value.Length;
    }
    
    このメソッドはパラメータとして文字列をとり、その長さを返します.文字列でテストを実行するときは、完全なメソッドをカバーし、ここで100 %に達しました.クール?さて、あなたがより密接に見るとき、あなたはそれに気がつきます.我々は本当に“品質”を確保するか?
    intはint 32ですstruct 最も低い値は-2147483648 そして最高2147483647 . stringのlengthプロパティはint 32の型ですので、文字列の理論長はint 32の最大値です.実際には、一般的な言語ランタイム(CLR)は2 GBで単一のオブジェクトのサイズを制限して以来、実際には、この数にも達することはありませんconfig しかし、通常その理由はない.デフォルトでは文字列はUTF - 16を使用します.これは1文字に対して2バイトを必要とします.畝
    OK、文字列の長さは何の問題も起こらないでしょう.文字列は、nullの権限を持つ参照型です.パラメーターがnullの場合、コードはクラッシュします.
    NullReferenceException
    マイポイント?まさにこれ.我々はこのメソッドで高いコードカバレッジを持っているにもかかわらず、我々はまだアプリケーションがクラッシュする可能性があります.畝
    私たちは、何が起こるかを理解するためのコンテクストを必要とします.コードカバレッジKPIについて多くのことを気にする代わりに、我々は異なるものをカバーするべきですuse cases and misuse cases .
    Use case and misuse case combined
    使用ケースがある目標を達成するための一連のステップを含むシステムとの間の相互作用を定義している間に、ユースケースはシステムに対して悪意ある行為のプロセスを記述する.しかし、どのように我々はコンテキストで品質を確保することができますか?
    我々は1つのステップを取る必要があります品質を定義し、どのような品質の特性は、品質を確保するために必要とされている
    質は条件的で、主観的であり、異なる人々によって異なって理解される.消費者が焦点を当てている間specification quality , プロデューサーconformance quality 心で.各グループの別のフォーカスを知って、我々は深く具体的に掘ることができます.これを行うには、定義された品質モデルを使用することができますISO 25010 これは、25000シリーズの一部としても知られている(システムとソフトウェアの品質要件と評価).
    最初のモデルは使用中の品質です.それはどのように製品の特定の目標を達成するためにユーザーのニーズを満たして示します.
    使用品質モデル
    第2の特徴は製品品質であり,8つの特徴からなる.
    システム/ソフトウェア製品品質モデル
    今これらの品質モデルを知ることは、さまざまな視点を通じて、使用方法と製品を見るのに役立ちます.これらの特性を念頭に置いて、要件を強化し、ニーズについてより具体的にすることができます.使用例と誤用例と共に、異なる機能および機能以外の要件に対するコードをテストすることができます.別のシナリオを知ってもあなた自身のkpisを構築することができます.高いコンテキストカバレッジで、また、本質的に高いコードカバレッジに到達しますが、これは他の方法で回避しません.
    あなたのコードを自動的にテストすることは重要です、そして、効果的なKPISで働くことはあなたが盲点に集中するのを援助します.いくつかのKPISは他のものよりも効果的ですので、KPIは誤った結論につながることができるので、データを収集し、結果を表示するために処理を念頭に置いています.