web-dev-qa-db-ja.com

ブランチカバレッジはループをどのように処理しますか?

コードカバレッジが一般的にどのように機能するかを知っており、ブランチカバレッジとは何かを知っています。しかし、ブランチカバレッジがループを処理する方法についての説明は見当たらないようです。

パスカバレッジのように機能しますか? 10回実行されるループは、11回実行されるまったく同じループとは異なるパスです。それとも、これら2つのケースはブランチのカバレッジで同じですか?

4
AntonNiklasson

ブランチカバレッジとパスカバレッジは異なる概念です。

ブランチカバレッジ

分岐カバレッジを測定するには、分岐が発生する可能性のあるすべてのポイントを探します。各分岐点で、両方の分岐が少なくとも1回実行されている必要があります。例えば。この疑似コードでは:

A
if B:
  C
else:
  D
E
if F:
  G
I

2つの分岐点– if Bおよびif F条件。完全なブランチカバレッジを取得するには、これらの条件のそれぞれがtrueとfalseのブランチを実行する必要があります。つまり、BFの両方がそれぞれfalseとtrueでなければなりません。テスト計画は次のようになります。

Run 1:
  B = false
  F = false
  # executes A B _ D E F _ I
Run 2:
  B = true
  F = true
  # executes A B C _ E F G I

ご覧のように、完全な分岐カバレッジは完全なステートメントカバレッジを意味します。

ループを処理するときは、条件とゴトのみを持つより低レベルの表現に「コンパイル」すると役立つ場合があります。例えば。:

// C99 code
A;
for (int i = 0; i < length; ++i)
  B;
C;

として理解できる

// Block 1
  A;
  int i = 0;

// Block 2
loop_start:
  if (!(i < length))
    goto loop_end;  // -> Block 4

// Block 3
  B;
  ++i;
  goto loop_start;

// Block 4
loop_end:
  C;

ここでは、ブロック2の条件は1つだけです。したがって、完全な分岐カバレッジを取得するには、falseとtrueの両方を一度評価する必要があります。テスト計画は次のようになります。

Run 1:
  length = 1
  # executes B1 B2 B3 B2 B4

したがって、このテスト計画では、ループ条件はtrueとfalseの両方に評価されます。しかし、明らかに、これは満足のいくテストではありません。ループが完全にスキップされるとどうなりますか(例:length = 0)?ループ本体がいくつかの状態を変更するとどうなりますか?それでも何百回もの繰り返しで動作しますか?

パスカバレッジ

コードを制御フローグラフにグループ化すると、パスカバレッジは、考えられるすべてのパスから取得したパスの割合を測定します。パスカバレッジは、ブランチカバレッジを意味します。最初の例を振り返ると、2つのテストケースのみでブランチカバレッジを取得できました。ただし、パスカバレッジを取得するには、4つのケースが必要です。最初の条件を通過するパスごとに2つ、2番目の条件の2つのケースを掛けたものです。

Run 1:
  B = false
  F = false
  # executes A B _ D E F _ I
Run 2:
  B = false
  F = true
  # executes A B _ D E F G I
Run 3:
  B = true
  F = false
  # executes A B C _ E F _ I
Run 4:
  B = true
  F = true
  # executes A B C _ E F G I

制御フローグラフにループが含まれている場合、一般に無限に多くの可能なパスがあります。場合によっては、ループの反復回数は定数によって制限され、テストすることができますが、一般的にはそうではありません。完全なパスカバレッジは便利ですが到達不可能であるため、他のカバレッジメトリックを使用する傾向があります。

テストを書くとき、ループのフルパスカバレッジを無視する傾向があります(単純な条件文のパスカバレッジは依然として非常に便利です)。ただし、テストのために複数のパスをグループ化して同等クラスにすることができます。0、1、2、および「多数」の反復でコードを実行すると、適切な近似になります。可能なテスト計画:

Run 1:
  length = 0
  # executes B1 B2 B5
Run 2:
  length = 1
  # executes B1 B2 B3 B2 B5
Run 3:
  length = 2
  # executes B1 B2 B3 B2 B3 B2 B5
Run 4:
  length = 123
  # executes B1 B2 B3 B2 B3 ... B2 B3 B2 B5

線形コードシーケンスとジャンプ-カバレッジなど、ループテストを定量化できる正式なコードメトリックもあります。しかし、私はそれを使用したことがありません。

再帰によるループのテスト

ループが再帰として表現される場合、ループは明示的ではないため、パスカバレッジから「隠されます」。これは問題ですか?やや。ループはプログラム全体の制御フローグラフにはまだ存在していますが、再帰関数のCFGにはありません。

ただし、再帰的に表現するとループが正しいことを示す方がはるかに簡単です。基本ケースと非基本ケースをテストできます。非ベースケースの各結果はベースケース(既に正しいことが示されています)から構築されているため、関数全体は正しいと推定できます。これは帰納法による証明手法に似ていますが、テストが正当性の証明ではなく、単なる正当性の例です。

8
amon