🎸

なぜC1カバレッジを採用するのか?:ホワイトボックスがブラックボックスを照らす

2024/04/22に公開

C1カバレッジとは

※C1カバレッジはブランチカバレッジと同義です。

https://youtu.be/zKSEF4lYOBc

C1カバレッジ、またはブランチカバレッジ(条件カバレッジとも呼ばれることがあります)は、ソフトウェアテストのカバレッジ指標の一つで、プログラム内の全ての可能な分岐(if文、ループなどの条件分岐を含む)が少なくとも一度は実行されるかどうかを測定します。このカバレッジの目的は、プログラムの論理的なパスを全て検証し、条件分岐に関連するバグや問題を発見することにあります。

サンプルコード

def user_message(age):
    if not isinstance(age, (int)):
        return "Error"
    if age >= 18:
        return "OK"
    else:
        return "NG"

# テストケース
def test_user_message():
    assert user_message("eighteen") == "Error", "非数値入力は'Error'を返すべき"
    assert user_message(17) == "NG", "18歳未満は'NG'を返すべき"
    assert user_message(18) == "OK", "18歳以上は'OK'を返すべき"

具体的には、C1カバレッジは各分岐点で可能な両方の結果(真と偽)がテストによって引き起こされることを保証します。例えば、if文がある場合、if文の条件がtrueにもfalseにもなるようなテストケースを準備する必要があります。これにより、プログラムの各分岐が意図した通りに機能するか、または予期せぬ挙動を示すかを確認できます。

上記サンプルで言うと、age=20はif文の条件がtrueであることを検証し、age=17はif文の条件がfalseであることを検証しています。

ホワイトボックスがブラックボックスを照らす

C1カバレッジを適切に意識することで、ホワイトボックステストであるユニットテストでブラックボックステストの領域もカバーできると考えています。下記のようなバリデーションのロジックを例を通じて説明します。

例として、年齢に基づく判定を行うシンプルなプログラムを考えてみましょう。

仕様

仮に、年齢を判定する画面があるとします。その仕様は以下の通りです。

  • 入力は数値のみ、数値でなければ"Error"を返します。
  • 数値を入力したとき、18歳以上であれば"OK"を返します。
  • 数値を入力したとき、18歳未満であれば"NG"を返します。

ソースコード

下記は、上記の仕様を満たす最低限のコード例です。

def user_message(age):
    if not isinstance(age, (int)):
        return "Error"
    if age >= 18:
        return "OK"
    else:
        return "NG"

テストコード

def test_user_message():
    assert user_message("eighteen") == "Error", "非数値入力は'Error'を返すべき"
    assert user_message(17) == "NG", "18歳未満は'NG'を返すべき"
    assert user_message(18) == "OK", "18歳以上は'OK'を返すべき"

同値分割

同値分割法で数値パーティションと非数値パーティションで分けて考えます。

  1. 有効な数値入力(年齢):

    • 18歳以上(例: 18歳、30歳)
    • 18歳未満(例: 17歳、0歳)
  2. 無効な入力:

    • 数値以外(例: 文字列 "eighteen"、空白、特殊文字 "@")

境界値分析

続いて、境界値分析で境界のテストケースを考えます。2値BVAで検討します。

  1. 18歳(有効範囲の下限値):

    • テストケース: 18歳 → 期待される結果: "OK"
  2. 18歳未満の境界値:

    • テストケース: 17歳 → 期待される結果: "NG"

テストケースのまとめ

  1. 数値以外の入力:

    • テストケース: "eighteen" → 期待される結果: "Error"
  2. 18歳未満の有効な入力:

    • テストケース: 0歳 → 期待される結果: "NG"
  3. 18歳の境界値テスト:

    • テストケース: 18歳 → 期待される結果: "OK"
  4. 18歳未満の境界値テスト:

    • テストケース: 17歳 → 期待される結果: "NG"

C1カバレッジと同値分割法・境界値分析との差異

「C1カバレッジと同値分割法境界値分析との差異」を理解することは、テスト戦略の設計において非常に重要です。C1カバレッジは、プログラムの各分岐が正しく機能しているかを検証するためのホワイトボックステストの手法です。これにより、コードの各パスが少なくとも一度はテストされることが保証されます。一方、同値分割法境界値分析は、入力データの異なるクラスに基づいてテストケースを設計するブラックボックステストの手法です。これらの手法は、特定の入力値や入力値の範囲がプログラムの挙動にどのように影響するかを評価するのに役立ちます。

しかし、これらのアプローチは相互に排他的ではなく、むしろ補完的です。C1カバレッジは、プログラムのロジックが正しく実行されることを保証する一方で、同値分割法境界値分析は、特定の入力に対するプログラムの挙動を深く理解するのに役立ちます。したがって、これらのテスト手法を組み合わせて使用することで、より包括的なテストカバレッジを実現し、ソフトウェアの品質を向上させることができます。

実際にテストプラクティスに組み込む際には、まずC1カバレッジを用いてコードの各パスが適切に機能していることを確認します。その後、同値分割法境界値分析を適用して、異なる入力値に対するプログラムの反応を詳細に検証することが推奨されます。このアプローチにより、単にコードが動作することを超えて、特定の条件下でのプログラムの正確な挙動を保証することが可能となります。

このようにして、C1カバレッジと同値分割法境界値分析の組み合わせを通じて、ソフトウェアテストの効果を最大化し、エンドユーザーに高品質なプロダクトを提供するための基盤を構築することができます。

C1カバレッジでは、同値分割法境界値分析で洗い出した下記のテストケースがありませんでした。

  1. 18歳未満の有効な入力:
    • テストケース: 0歳 → 期待される結果: "NG"

品質保証の観点からは、0歳のケースをテストしたいです。仮にこのメソッドで問題がなくても、別のコードで潜在的な欠陥が見つかる可能性があるためです。

とはいえ、4つのテストケース中3つのテストケースを満たしているため、C1カバレッジを採用する根拠となり得ます。

終わりに

なぜC1カバレッジを採用するのか?を次の観点で引き続き考えたいと考えています。

  • C0カバレッジ(ステートメントカバレッジ)との比較
  • コードの複雑さへの対応
  • エッジケースの検出
  • リファクタリングとの相性
  • テストの品質向上
  • テスト自動化との相乗効果

Discussion