コードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味

  1. ホーム
  2. ブログ
  3. ソフトウェアテスト

ソフトウェアテスト

コード カバレッジの説明: ライン カバレッジとブランチ カバレッジ、および 100% の実際の意味

カバレッジにより、テストでどのコードが実行されたかがわかります。テストで何かがチェックされたかどうかはわかりません。違いを示すために、小さなモジュールを 3 つの方法で測定しました。

読了目安8分
コードカバレッジの説明: ラインカバレッジとブランチカバレッジ、および 100% の実際の意味

ポイント

  • コードカバレッジテスト中に実行されるコードの量を測定します。
  • ブランチ カバレッジはライン カバレッジよりも厳密であり、より便利です。
  • 私たちのテストでは、アサーションなしのスイートでも 100% のカバレッジに達しました。
  • カバレッジは、品質の証明としてではなく、テストされていないコードを見つけるために使用します。

あるチームは誇らしげに 95% のコード カバレッジを報告し、「カバーされた」行にバグを出荷します。これは矛盾ではありません。このカバレッジは、テストでこのコードが実行されたのかという 1 つの狭い質問に答えています。彼らが結果を確認したかどうかはまったく別の問題です。

Python では、coverage.py 7.17 と pytest 9.2 を使用しました。以下のすべての数値とレポートは、当社が独自に実行したものです。この考え方はどの言語にも当てはまります。

コードカバレッジとは何ですか?

コード カバレッジは、自動テストの実行中に実行されるコードの割合です。ツールは、どの行、およびオプションでどの分岐が実行されたかを記録し、何が欠落したかを報告します。

逆に使うと最も便利です。ある領域のカバー率が低いということは、テストがその領域を実行していないことを確実に示しています。カバレッジが高いと、得られる情報ははるかに少なくなります。

補償の種類

種類 質問に答える
機能 各関数は少なくとも 1 回呼び出されましたか?
行(ステートメント) 各ラインは少なくとも 1 回は実行されましたか?
支店 それぞれの if は真と偽の両方の方向に進みましたか?
状態 結合条件 (a and b) の各部分は両方の値を取りましたか?
MC/DC それぞれの条件が独立して結果を変えましたか?安全性が重要なソフトウェアで使用されます。

各レベルはその上のレベルよりも厳格です。ほとんどのチームはラインと支店のカバレッジを追跡しています。条件カバレッジと MC/DC は航空および自動車の規格に登場し、ツーリングのサポートが専門化されています。

測定したコード

def shipping_fee(total, is_member, express=False):
    if total < 0:
        raise ValueError("total cannot be negative")
    fee = 0 if total >= 1000 else 50
    if is_member:
        fee = max(fee - 25, 0)
    if express:
        fee += 100
    return fee

最初のテスト ファイルには 2 つのテストがありました。

def test_regular_order():
    assert shipping_fee(500, False) == 50

def test_member_express():
    assert shipping_fee(500, True, express=True) == 125

ブランチ測定をオンにして実行しました。

coverage run --branch -m pytest test_shipping.py
coverage report -m

レポートを読む

Name          Stmts   Miss Branch BrPart  Cover   Missing
---------------------------------------------------------
shipping.py       9      1      6      1    87%   3
  • Stmts 9、Miss 1: 9 つの実行可能ステートメントのうち、1 つは実行されませんでした。
  • 分岐 6、BrPart 1: 3 つの if 決定により、6 つの可能な結果が得られます。一つの決断は決して一方向にしか進まない。
  • Missing 3: 行 3、raise ValueError は実行されませんでした。合計がマイナスのテストに合格しませんでした。

修正はエラー パスのテストです。また、大規模注文用のテストも追加しました。

def test_free_over_1000():
    assert shipping_fee(1000, False) == 0

def test_negative_total():
    with pytest.raises(ValueError):
        shipping_fee(-1, False)

どちらのファイルでも、レポートには 100% と表示され、欠落行や部分的な分岐はありませんでした。エラー パスは古典的なギャップ カバレッジの検出方法です。そのため、等価分割 などの手法で設計された無効な入力のテストが、エラー パスと非常によく組み合わされます。

報告書が隠したこと

もう一度最初のレポートを見てください。 3行目だけが欠落しているとのことでした。しかし、最初の 2 つのテストでは両方とも合計 500 個を使用したため、1,000 個以上の注文に対する送料無料ルールは 一度もテストされておらず、レポートでもフラグを立てていませんでした。

その理由は、fee = 0 if total >= 1000 else 50 が 1 行に収まっているためです。 coverage.py は行間の分岐を測定するため、単一行内の条件式は 1 つの実行されたステートメントとしてカウントされます。このルールにバグ (>= ではなく > など) があったとしても、最初のスイートはヒントなしで 87% を示していたでしょう。 境界値分析で説明されているように、境界自体のテストがそれを捕捉します。

チェックなしで 100% カバー

次に、すべてのパスを呼び出しますが、何もアサートしない、意図的に貧弱なテストを作成しました。

def test_runs_everything_but_checks_nothing():
    shipping_fee(500, True, express=True)
    shipping_fee(1000, False)
    shipping_fee(500, False)
    try:
        shipping_fee(-1, False)
    except ValueError:
        pass
shipping.py       9      0      6      0   100%

回線および支店のカバレッジが 100%に達しました。この関数は任意の数値を返すことができ、このテストは合格します。これはカバレッジの中核となる制限であり、検証ではなく実行を測定します。

ヒント: プル リクエストをレビューするときは、カバレッジの変更だけでなくアサーションも読んでください。意味のあるアサートを行わずにカバレッジを追加するテストは、誤った信頼性を追加するだけです。

テストが実際にバグを検出するかどうかを測定するには、突然変異テストを使用します。 Python の mutmut、Java の PIT、JavaScript の Stryker などのツールは、>= を > に反転するなどの小さな変更をコードに加え、テストが失敗するかどうかを確認します。私たちの非アサートテストでは、すべての突然変異が生き残ることになります。

どのような目標を設定するか

普遍的に正しい数字はありません。実践的なガイダンス:

  • 100% を追求しないでください。 最後の数パーセントは、多くの場合、簡単なコードのテストや、行に触れるだけのテストの作成を意味します。
  • 多くのチームは全体で約 70 ~ 85% を目指しており、コア ビジネス ロジックにはより高い期待が寄せられています。
  • 数値ではなく、傾向に注目してください。 リリースごとにカバー率が低下している場合は、危険信号です。
  • 古いコードを一度に強制的にアップするのではなく、プル リクエストで新しいコードのカバレッジを要求します。
  • 明確なルールに従って、生成されたコードなど 重要でないものを除外します。

グッドハートの法則が適用されます。つまり、ある尺度が目標になると、それは良い尺度ではなくなります。ハード ターゲットは、アサートなしの例のようなテストを奨励します。

言語ごとのツール

言語 共通ツール
パイソン カバレッジ.py、pytest-cov
JavaScript / TypeScript イスタンブール (ニューヨーク)、Jest と Vitest に組み込まれています
ジャワ ジャココ
.NET ベッドカバー
行く テストに行く - カバー
レポート Codecov、SonarQube、カバーオール

CI の範囲

CI パイプラインの一部としてカバレッジを実行し、レポートを公開して、レビュー担当者がどの新しい行がテストされていないかを確認できるようにします。 coverage.py では、coverage report --fail-under=80 はしきい値を下回るとビルドに失敗します。しきい値は控えめに保ち、新しいコードのルールと組み合わせてください。これにより、単一の大きなレガシー ファイルによってすべての変更がブロックされることがなくなります。

対象範囲を超えて: 尋ねるべきより良い質問

  • テストは、コードの危険な、頻繁に変更される部分をカバーしていますか?
  • 幸せなパスだけでなく、境界とエラーパスもテストされていますか?
  • この行が間違っていたらテストは失敗しますか?
  • テストは変更のたびに実行できるほど高速で安定していますか?

これらは任意のテスト戦略に属します。カバレッジは最初の答えのみに役立ちます。

コードの除外と HTML レポートの読み取り

デバッグ ヘルパーやスクリプトが手動で開始された場合にのみ実行されるブロックなど、一部のコードは直接テストする価値がありません。 coverage.py を使用すると、コメントを含む行を除外できます。

if __name__ == "__main__":  # pragma: no cover
    main()

たとえば pyproject.toml のように、構成で除外対象と測定するソース フォルダーを設定することもできます。

[tool.coverage.run]
branch = true
source = ["shop"]

[tool.coverage.report]
show_missing = true
exclude_also = ["if TYPE_CHECKING:"]

除外は慎重に使用し、コードと同じように確認してください。それぞれは、一部の行は決してチェックされないという決定です。数値を上げるためだけにテストが難しいエラー ハンドラーを除外するのは、目的に反します。

日常的な作業では、ターミナル テーブルよりも HTML レポートの方が便利です。 coverage htmlを実行し、htmlcov/index.htmlを開きます。各ファイルは、実行された行が緑色、失敗した行が赤色、部分的な分岐が黄色で表示されるため、if が他のパスを選択しなかったことが一目でわかります。多くのエディターでは、マージンにカバレッジを表示することもできます。これにより、コードを書いた後ではなく、作成中にギャップが見えるようになります。

リファクタリング前のカバレッジ

カバレッジは、リファクタリング前の安全性チェックでもあります。モジュールを再構築する予定がある場合は、まずそのレポートを確認してください。赤い領域には動作が変化した場合に警告するテストがないため、開始する前に現在の動作を把握する特性評価テストを追加してください。このように使用すると、カバレッジは目標ではなくなり、実用的な計画ツールになります。

同じレポートは、バグが運用環境に漏れた場合に役立ちます。バグが存在する行を見つけて、テストでそのバグが実行されたかどうかを確認します。そうでない場合は、埋める価値のあるギャップを見つけたことになります。テストで実行された場合、問題は弱いアサーションであり、これはまさに、非アサートの例で示した状況です。どちらの答えも、スイートを改善する方法を示しています。

まとめ

コードカバレッジはグレードではなく懐中電灯です。ブランチ カバレッジを使用して、テストが触れていないコード (特にエラー処理) を見つけて、実際のアサーションを行うテストを作成します。実行結果の 1 つを覚えている場合は、次のようにしてください。何もチェックしないテストで 100% のカバレッジに達しました。

よくある質問

テストにおけるコードカバレッジとは何ですか?

これは、自動テストの実行中に実行されたコードの割合であり、行、分岐、または条件によって測定されます。テストが検証したかどうかではなく、テストが何に影響したかを示します。

回線カバレッジとブランチカバレッジの違いは何ですか?

回線カバレッジは、各回線が実行されたことをチェックします。ブランチカバレッジは、それぞれの決定が双方向で行われたことをチェックします。ブランチ カバレッジは、ライン カバレッジが見逃した未テストのパスを見つけます。

100% のコード カバレッジは良好ですか?

それ自体ではありません。私たちのテストでは、アサーションのないスイートは 100% に達しました。重要なコードについては、完全な数ではなく意味のあるテストを目指してください。

適切なコード カバレッジ パーセンテージとは何ですか?

多くのチームは全体でおよそ 70 ~ 85% を目標にしており、クリティカル ロジックについてはさらに重点を置いています。正確な数値よりも、アサーションの傾向と質の方が重要です。

突然変異テストはカバレッジとどう違うのですか?

ミューテーション テストではコードをわずかに変更し、テストが失敗するかどうかを確認します。カバレッジではできないテストでバグが検出されるかどうかを測定します。

学び続ける

Stack Quoraと連携する

テスト、WordPress、または SEO についてサポートが必要ですか?

私たちは、チームがより優れたソフトウェアを出荷し、サイトを成長させるのを支援します。あなたが取り組んでいることを教えてください。明確な次のステップを提案します。

読み続けてください

詳しいガイドはこちら テスト、AI、最新の開発

この記事は気に入りましたか?トピックを選択して、最新のチュートリアルに直接アクセスしてください。

人工知能

AI 幻覚の説明: 言語モデルが物事をでっち上げる理由とそれを軽減する方法

AI 幻覚について説明しました。幻覚とは何か、言語モデルが幻覚を生成する理由、一般的な種類、グラウンディングとプロンプトで幻覚を軽減する方法、そして私たちが実行した簡単なチェックです。

記事を読む →
DevOps

環境変数の説明: .env ファイル、シークレット、および設定が正しく行われている

実行した Python の例を使用して環境変数について説明します。環境変数の読み取りと設定、すべての値が文字列である理由、.env ファイル、プロセスの継承、シークレット、検証について説明します。

記事を読む →
ソフトウェア開発

API レート制限の説明: アルゴリズム、ヘッダー、および 429 エラーの処理

API レート制限については、実行したシミュレーションで説明します。トークン バケット、固定ウィンドウ、スライディング ウィンドウ、429 応答、レート制限ヘッダー、バックオフによる再試行、およびテスト制限です。

記事を読む →
テスト自動化

Python でのモッキング:unittest.mock、patch、およびテストを嘘にする間違い

Python でのunittest.mockによるモック、テスト済み: モックとreturn_value、side_effect、名前が使用されている場所のパッチ、仕様と自動仕様、日付のモック、およびよくある間違い。

記事を読む →
ソフトウェアテスト

コードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味

実際のcoverage.pyの実行でコードカバレッジを説明: 行、分岐、条件のカバレッジ、レポートの読み取り、100%のカバレッジでもバグを見逃す可能性がある理由、および賢明なターゲット。

記事を読む →
データベースとSQL

SQL における DELETE、TRUNCATE、DROP: 違い、ロールバック、およびそれぞれをいつ使用するか

DELETE、TRUNCATE、DROP について、テスト済み SQL を使用して説明します。それぞれの削除内容、ロールバック、トリガー、ID リセット、速度、PostgreSQL、MySQL、SQL Server、SQLite の違いについて説明します。

記事を読む →
データベースとSQL

SQL ビューの説明: 作成、使用、落とし穴の回避、例を示します

SQL ビューについて、実行したクエリとともに説明しました。ビューの作成、ライブ結果、列の非表示、パフォーマンス、更新可能なビューと具体化されたビュー、壊れた依存関係、ベスト プラクティスについて説明します。

記事を読む →
ソフトウェア開発

TypeScript インターフェイスと型: 実際の違い、コンパイラでテスト

TypeScript インターフェイスと型、実際のコンパイラでチェック: 両方でできること、片方だけでできること、宣言のマージ、拡張と交差、および従うべき簡単なルール。

記事を読む →
ソフトウェア開発

Python *args と **kwargs の説明: 柔軟な関数と明確な例

Python の *args と **kwargs について、実行したコードで説明しました。パッキングとアンパッキング、パラメーターの順序、キーワードのみの引数と位置のみの引数、デコレーター、一般的なエラーです。

記事を読む →
ソフトウェア開発

Python Lambda 関数: 構文、実際の用途、および使用すべきでない場合

Python のラムダ関数について、実行したコードとともに説明します。構文、キーによるソート、マップとフィルター、クロージャー、遅延バインディング トラップ、通常の def がより適切な選択である場合。

記事を読む →
人工知能

AIエージェントとは何ですか?シンプルなエージェント ループを実行できる仕組み

AIエージェントとは何ですか?エージェント ループ、ツール、メモリ、ガードレール、実行した小さな Python ループ、実際のリスク、およびシンプルなチャットボットがより良い選択である場合についてのわかりやすいガイドです。

記事を読む →
DevOps

モニタリングと可観測性: ログ、メトリクス、トレースによる本当の違い

モニタリングと可観測性について説明: 既知および未知の障害、ログ、メトリクスとトレース、チェックアウト インシデントのウォークスルー、ゴールデン シグナル、OpenTelemetry、および便利なアラート。

記事を読む →
DevOps

Docker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する

Docker ボリュームとバインド マウントについて説明します。コンテナ データが消える理由、名前付きボリューム、バインド マウント、tmpfs、Compose の例、バックアップ、アクセス許可、およびそれぞれをいつ使用するかについて説明します。

記事を読む →
テスト自動化

TDD と BDD: 主な違い、1 つの機能が両方の方法で構築され、それぞれをいつ使用するか

TDD と BDD は、両方の方法で構築された 1 つの割引機能で説明されています。実行したコードによるレッド-グリーン-リファクタリング、Given-When-Then シナリオ、ツール、トレードオフ、およびそれぞれをいつ使用するかです。

記事を読む →
ソフトウェアテスト

ユーザー受け入れテスト (UAT): プロセス、チェックリスト、および実際の例

ユーザー受け入れテストの説明: 誰が実行するか、QA との違い、7 段階のプロセス、UAT テスト ケース テンプレート、チェックリスト、サインオフ基準、およびよくある間違い。

記事を読む →
データベースとSQL

SQL NULL 値の説明: IS NULL、COALESCE、NULLIF、および回避すべきトラップ

SQL の NULL 値について、実行したクエリで説明しました。3 つの値のロジック、IS NULL、COALESCE、NULLIF、集計、結合、並べ替えでの NULL の扱い方、およびそれが密かに引き起こすバグです。

記事を読む →
データベースとSQL

SQL CASE WHEN ステートメント: 構文、実際の例、およびよくある間違い

SQL CASE WHEN では、単純な検索フォーム、条件順序、SUM を使用したピボット、COUNT トリック、カスタム並べ替え、更新、回避すべき NULL トラップなど、実行したクエリを使用して説明しました。

記事を読む →
ソフトウェア開発

JWTとは何ですか? JSON Web トークンを実際の例で説明する

JWTとは何ですか? JSON Web トークンについて説明しました。3 つの部分、実行したコード内で構築および改ざんされたトークン、JWT とセッション、ストレージ、リフレッシュ トークン、およびセキュリティ上の間違いです。

記事を読む →
ソフトウェア開発

JavaScript イベントループの説明: コールスタック、マイクロタスク、タイマーと例

JavaScript イベント ループについて、実行したコードで説明しました。コール スタック、タスク キュー、マイクロタスク キュー、setTimeout 0 が即時ではない理由、ブロッキング、スターベーション、およびインタビュー クイズです。

記事を読む →
ソフトウェア開発

Python ジェネレーターと収量の説明: 実際の例でメモリを節約する

Python ジェネレーターと Yield について、実行したコードを使用して説明します。一時停止と再開の方法、メモリ節約の測定、パイプライン、無限シーケンス、Yield from、send、および一般的なトラップについて説明します。

記事を読む →
人工知能

埋め込みとは何ですか?ベクトルとコサインの類似度を簡単に説明

埋め込みとは何ですか?ベクトル、コサイン類似度、セマンティック検索に関する平易なガイド。私たちが実行した小さな例、一般的な使用法、モデルの選択、既知の制限が含まれています。

記事を読む →
DevOps

Blue-Green デプロイメントと Canary デプロイメント: 違い、トレードオフ、および選択方法

ブルー グリーン デプロイメントとカナリア デプロイメントについて説明: それぞれの仕組み、コスト、リスクとロールバック、テストした安定したユーザー バケット化、データベース移行、ローリング アップデート、および選択方法。

記事を読む →
テスト自動化

不安定なテスト: 問題の原因とそれを永久に修正する方法

不安定なテストについては、私たちが実行したデモを使用して説明しました。主な原因、確認および診断する方法、タイミングの適切な修正、共有された状態と日付、隔離プロセスなどです。

記事を読む →
ソフトウェアテスト

負荷テストとストレス テスト: 違い、メトリクス、および k6 の例

ロード テストとストレス テストについて説明します。それぞれが何を証明するか、スパイク テストとソーク テスト、重要な指標、平均値が誤解を招く理由、K6 の例、テストの計画方法について説明します。

記事を読む →
ソフトウェアテスト

テスト ケースとテスト シナリオ: 主な違い、例、およびそれぞれをいつ使用するか

テスト ケースとテスト シナリオの説明: 明確な定義、並べて表、シナリオからケースへの 1 つのパスワード リセット機能、テンプレート、およびそれぞれをいつ使用するか。

記事を読む →
データベースとSQL

SQL クエリの最適化: 実行プランを読み取り、タイミングを考慮して遅いクエリを修正

SQL クエリの最適化は 100 万行でテストされています。実行プランの読み取り、適切なインデックスの追加、検索対象外のフィルターの修正、複合インデックスとキーセットのページネーションの使用。

記事を読む →
データベースとSQL

SQL UNION と UNION ALL: 違い、例、テストされたパフォーマンス

SQL UNION と UNION ALL について、実行したクエリで説明しました。重複、両方に従うルール、実際のデータのバグ、測定されたパフォーマンス、INTERSECT と EXCEPT、およびそれぞれをいつ使用するかについて説明します。

記事を読む →
ソフトウェア開発

JavaScript Fetch API チュートリアル: GET、POST、エラー処理、タイムアウト

ローカル サーバーに対してテストされた JavaScript Fetch API チュートリアル: GET と POST、404 がスローされない理由、再利用可能なヘルパー、クエリ文字列、タイムアウト、CORS、およびよくある間違い。

記事を読む →
ソフトウェア開発

Python ファイル処理: 読み取り、書き込み、CSV、JSON、パスライブラリと例

Python のファイル処理について、実行したコードで説明します。オープン モード、大きいファイルの読み取り、CSV、JSON、パスライブラリ、バイナリ ファイル、安全な書き込み、エラー処理、およびよくある間違いについて説明します。

記事を読む →
ソフトウェア開発

Python のクラスとオブジェクト: 実際の例を含む OOP チュートリアル

Python のクラスとオブジェクトについて、実行したコードとともに説明します: __init__、メソッド、クラスとインスタンスの属性、継承、プロパティ、ダンダー メソッド、データクラス、およびよくある間違い。

記事を読む →
人工知能

大規模言語モデルとは何ですか? LLM の仕組みを誇大広告なしで説明

大規模言語モデルとは何ですか? LLM は、トークン、エンベディング、アテンション、トレーニング、温度およびコンテキスト ウィンドウ、小さな次の単語のデモ、実際の制限など、平易な言葉で説明されています。

記事を読む →
DevOps

初心者のための Linux コマンド: 例を含む基本ターミナル ガイド

初心者向けの Linux コマンド。ナビゲーション、ファイル、ログの表示、grep、パイプ、権限、プロセス、アーカイブなどのタスク別にグループ化されており、実用的なログ分析の例も含まれています。

記事を読む →
テスト自動化

Selenium と Playwright: 主な違い、コードの比較、どちらを選択するか

Selenium と Playwright の比較: アーキテクチャ、待機、ブラウザと言語のサポート、デバッグ、両方のツールでの同じテスト、移行のアドバイスと選択方法。

記事を読む →
ソフトウェアテスト

等価性分割: テスト設計手法を実際の例で説明

等価性パーティション化について説明しました。有効なパーティションと無効なパーティションを見つける方法、年齢、パスワード、クーポンに関する実際の例、実行したテスト、境界と組み合わせる理由。

記事を読む →
ソフトウェアテスト

ソフトウェアテストにおける重大度と優先度: 相違点、マトリックス、および実際の例

ソフトウェア テストにおける重大度と優先度について説明します。明確な定義、例を含む 4 方向のマトリックス、レベル スケール、それぞれの設定者、バグ トリアージの実行方法。

記事を読む →
データベースとSQL

SQL サブクエリのチュートリアル: 型、相関サブクエリ、および EXISTS と例

実行したクエリを含む SQL サブクエリのチュートリアル: スカラー、IN、FROM、SELECT サブクエリ、相関サブクエリ、EXISTS、NOT IN NULL トラップ、サブクエリ対 JOIN 対 CTE。

記事を読む →
データベースとSQL

SQL トランザクションと ACID の説明: COMMIT、ROLLBACK、分離レベル

SQL トランザクションと ACID について、実行した銀行振込で説明しました。COMMIT、ROLLBACK、セーブポイント、ロック、分離レベル、ダーティ リード、デッドロック、ベスト プラクティスについて説明します。

記事を読む →
ソフトウェア開発

Git mergeとrebaseの違い:例と使い分け

Git mergeとrebaseの違いを、実際のログ出力、比較表、rebaseの黄金律、安全なチームワークフローで解説します。

記事を読む →
ソフトウェア開発

Pythonのリスト内包表記:構文・例・使うべきでない場面

Pythonのリスト内包表記を解説:構文、フィルタ、if-else、ネストしたループ、実測した処理時間、そして通常のforループの方が良い場面。

記事を読む →
データベースとSQL

SQL JOINを例で解説(Inner・Left・Right・Full)

サンプルのテーブルとクエリでSQL JOINを順に解説。INNER、LEFT、RIGHT、FULL、CROSS、SELFに加え、よくある間違いとパフォーマンスのコツも紹介します。

記事を読む →