🦁

テストカバレッジ C0/C1/C2/MCC の解説

に公開

C0(命令カバレッジ)

  • C0は、プログラム内のすべての**命令(行)**が少なくとも一度は実行されたかどうかを測定します。

  • 例:checkEvenOdd(2) を実行すると、"Even" が表示され、if 文の中の命令が実行されます。しかし、else の部分は実行されていません。このため、C0カバレッジは部分的にしか満たされません。checkEvenOdd(3) を実行すると、else の部分が実行され、C0カバレッジが100%になります。

    if (num % 2 !== 0) return;
    

C1(分岐カバレッジ)

  • C1は、プログラム内のすべての**分岐(if, else if, else)**のパスが通過されたかを測定します。

  • 例:

    function checkSign(num) {
      if (num > 0) {
        console.log("Positive");
      } else if (num < 0) {
        console.log("Negative");
      } else {
        console.log("Zero");
      }
    }
    

    このコードには3つの分岐があります。

    • checkSign(5)if (num > 0) が True で "Positive" と表示。
    • checkSign(-5)else if (num < 0) が True で "Negative" と表示。
    • checkSign(0)else が True で "Zero" と表示。

    これら3つのテストケースをすべて実行することで、C1カバレッジは100%になります。すべての分岐のTrue/Falseがテストされる必要があります。

C0・C1の違い(カバレッジ100%にするには)

C1(分岐カバレッジ)は、すべての条件分岐がテストされたかどうかを確認します。これには、各条件がTrueまたはFalseの両方の場合がテストされる必要があります。

C1カバレッジを100%にするには?

  • この関数には、2つの分岐があり、それぞれの結果(True/False)を確認する必要があります。
  1. if (num > 0)
    • True の場合 → checkSign(5) を実行すると、「Positive」が表示されます。
    • False の場合 → checkSign(0) または checkSign(-5) を実行すると、次の分岐に進みます。
  2. else if (num < 0)
    • True の場合 → checkSign(-5) を実行すると、「Negative」が表示されます。
    • False の場合 → checkSign(0) を実行すると、最後の else に進みます。

結論

  • checkSign(5) は、if (num > 0)True の場合をカバーします。
  • checkSign(-5) は、else if (num < 0)True の場合をカバーします。
  • ただし、C1カバレッジを100%にするためには、checkSign(0) を実行して、else に到達する必要があります

checkSign(0) を実行しない場合、else の分岐がカバーされないため、C1カバレッジは100%にはなりません。すべての分岐(True/Falseの道)が通らないと、C1カバレッジは100%とみなされないのです。

したがって、checkSign(0) を実行して初めて、全ての条件のパス(True/False)を通ったことになり、C1カバレッジが100%になります。

C2(条件カバレッジ)

  • C2は、すべての条件の組み合わせがテストされたかどうかを確認します。複数の条件がある場合、それぞれの条件がTrue/Falseになるケースを全てテストする必要があります。

  • 例:

    function checkEligibility(age, hasLicense) {
      if (age >= 18 && hasLicense) {
        console.log("Eligible to drive");
      } else {
        console.log("Not eligible to drive");
      }
    }
    

    この場合、age >= 18hasLicense の2つの条件があります。
    テストケース:

    • checkEligibility(20, true) → True, True
    • checkEligibility(16, true) → False, True
    • checkEligibility(20, false) → True, False
    • checkEligibility(16, false) → False, False

    これら4つのケースですべての条件の組み合わせをテストし、C2カバレッジが100%になります。

MCC(循環的複雑度)

  • MCC(循環的複雑度)は、コード内の独立した実行パスの数を測定します。これはコードの複雑さを数値化するもので、分岐が多いほど値が高くなります。

  • 計算式:MCC=E−N+2PMCC=6−8+2=0

    MCC=E−N+2PMCC = E - N + 2P

    • E: 分岐(エッジ)の数
    • N: ノード(命令や条件)の数
    • P: プログラムのエントリポイントの数(通常1)

    例:

    function determineAction(weather, temperature) {
      if (weather === "sunny") {
        if (temperature > 25) {
          console.log("Go to the beach");
        } else {
          console.log("Go for a walk");
        }
      } else if (weather === "rainy") {
        console.log("Stay indoors");
      } else {
        console.log("Check the forecast");
      }
    }
    
    

    この場合、MCCを計算するために次のようにノードとエッジを数えます。

    • ノード数(N): 8
    • エッジ数(E): 6
    • エントリポイント(P): 1

    計算すると、

    MCC=6−8+2=0MCC = 6 - 8 + 2 = 0

    よって、このコードの循環的複雑度は 2 です。

MCC(循環的複雑度)とは?

MCC(McCabeの循環的複雑度)は、プログラムのコードがどれだけ複雑か、またはどれだけの異なる実行パス(コードの流れ)が存在するかを数値で表す指標です。MCCの値が高いと、そのコードには多くの異なる実行経路があり、バグのリスクが増え、テストもしっかりしなければならないことを意味します。

MCCを使う理由

プログラムが複雑になるほど、テストすべき分岐やルートが増えていきます。MCCを使ってプログラムの複雑さを数値で把握し、テスト計画やコードの品質改善に役立てることができます。

MCCは、分岐がどれだけあるかに着目します。分岐は、if 文や for ループ、while ループ、switch 文などが例です。それぞれの分岐は、プログラムがいくつかの異なるルートを通る可能性を生み出します。


MCCを数える方法

MCCを数えるには、次の式を使います:

MCC=E−N+2P\text{MCC} = E - N + 2P

MCC=E−N+2P

  • E(エッジ): プログラムの分岐の数(各条件やループによって新しく生まれるルート)
  • N(ノード): プログラムのノードの数(分岐や命令のポイント)
  • P(エントリポイント): プログラムの開始点。通常は1。

実際の例で見てみましょう

次のコードを例にします。


function determineAction(weather, temperature) {
  if (weather === "sunny") {
    if (temperature > 25) {
      console.log("Go to the beach");
    } else {
      console.log("Go for a walk");
    }
  } else if (weather === "rainy") {
    console.log("Stay indoors");
  } else {
    console.log("Check the forecast");
  }
}

1. ノード(N)を数える

ノードは、プログラムの分岐や命令の数を表します。このプログラムには次のノードがあります。

  • if (weather === "sunny") → ノード1
  • if (temperature > 25) → ノード2
  • console.log("Go to the beach") → ノード3
  • console.log("Go for a walk") → ノード4
  • else if (weather === "rainy") → ノード5
  • console.log("Stay indoors") → ノード6
  • else → ノード7
  • console.log("Check the forecast") → ノード8

ノードの合計 = 8

2. エッジ(E)を数える

エッジは、プログラムの分岐によって生まれる新しいルートです。例えば、if 文や else でコードの実行が異なる場合、1つの分岐から2つのエッジが生まれます。

  • if (weather === "sunny") → True/False → 2つのエッジ
  • if (temperature > 25) → True/False → 2つのエッジ
  • else if (weather === "rainy") → True/False → 2つのエッジ

エッジの合計 = 6

3. エントリポイント(P)

エントリポイントは、プログラムの開始点です。通常、1つのプログラムには1つのエントリポイントしかありません。

エントリポイント = 1


MCCを計算する

今、MCCの公式に当てはめて計算します。

MCC=E−N+2PMCC = E - N + 2P

MCC=E−N+2P

  • E = 6 (エッジの数)
  • N = 8 (ノードの数)
  • P = 1 (エントリポイントの数)

これを公式に当てはめると:

MCC=6−8+2(1)=0MCC = 6 - 8 + 2(1) = 0

MCC=6−8+2(1)=0

結果:

MCC=2MCC = 2

MCC=2


MCCの解釈

  • MCC = 1 の場合:非常にシンプルなプログラム(分岐なし)。
  • MCC = 2 の場合:いくつかの分岐があるが、比較的シンプルなプログラム。
  • MCCが高ければ高いほど、プログラムは複雑で、異なる実行パスが多くなります。そのため、テストすべきルートが増え、バグが潜む可能性も増えるということです。

まとめ

  • MCCは、コード内の分岐やループなどを考慮して、どれだけの異なる実行パスがあるかを示す指標です。
  • 値が大きいほど、コードは複雑であり、多くのパスがテストされる必要があります。
  • MCCを理解することで、コードのテストがどれだけ必要か、そしてコードの複雑さがどれだけ高いかを把握できます。

このようにして、MCCを使うと、プログラムがどれだけテストされるべきかや、コードの改善点が見つけやすくなります。

4o

Bizlink Developers Blog

Discussion