閉じる

Pythonのテストカバレッジを測る方法(pytest-cov)とHTML出力

テストを書いたあと、そのテストがコードのどこまで実行しているのかを数値で把握できると、抜け漏れに気づきやすくなります。

本記事では、pytestの拡張であるpytest-covを使ってテストカバレッジを計測し、ターミナル表示とHTMLレポートで網羅性を確認する方法を、初心者の方向けに丁寧に解説します。

Pythonのテストカバレッジとは?pytest-covの基本

テストカバレッジ(coverage)の意味

テストカバレッジは、テスト実行時にどのコードが実際に実行されたかを割合で示す指標です。

一般的には行カバレッジ(line coverage)が使われ、全行のうち実行された行の割合(%)を示します。

加えて分岐カバレッジ(branch coverage)を測ると、ifなど条件分岐の各経路を通ったかもわかります。

カバレッジの数値は「品質そのもの」ではありませんが、抜け落ちたテスト箇所に気づくための強力な指標です。

pytestとpytest-covの関係

pytestはPythonの標準的なテストランナーです。

pytest-covは、そのpytestにカバレッジ計測機能を追加するプラグインで、内部的にはcoverage.pyという実績あるライブラリを利用しています。

これにより、pytestのコマンドにオプションを付けるだけで、カバレッジの測定やレポート出力が可能になります。

初心者が押さえるポイント

  • いつも--cov=パッケージ名を付けると、測定対象が明確になり、不要なライブラリまで集計されるのを防げます。
  • 数値を上げることが目的化しないようにし、--cov-report=term-missingやHTMLレポートで「どの行が未実行か」を見て具体的に改善しましょう。
  • 分岐の網羅性も確認したい場合は--cov-branchを使います。

pytest-covの導入と基本の使い方

インストール(pip install pytest-cov)

まずはpytest本体とpytest-covをインストールします。

仮想環境(venv)の利用をおすすめします。

Shell
# (任意) 仮想環境を作成して有効化
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

# pytest と pytest-cov をインストール
pip install pytest pytest-cov

最小の実行例(pytest –cov)

以下は最小のサンプルプロジェクトです。

プロジェクトルートでpytestを実行することが重要です。

text
your_project/
├─ app/
│  ├─ __init__.py # 中身は空でOK
│  └─ calculator.py
└─ tests/
   └─ test_calculator.py
Python
# app/calculator.py
# シンプルな関数をいくつか定義します。条件分岐を入れて、分岐カバレッジの例にも使います。

def add(a, b):
    """2つの数値を足し合わせます。"""
    return a + b

def divide(a, b):
    """0除算を考慮しながら割り算を行います。"""
    if b == 0:
        # ここは例外を発生させる分岐です
        raise ZeroDivisionError("b must not be zero")
    return a / b

def safe_divide(a, b, default=None):
    """0除算時にデフォルト値を返す安全な割り算。default未指定ならNoneを返します。"""
    if b == 0:
        # 条件に応じて2通りの経路があります
        return default if default is not None else None
    return a / b

def greet(name):
    """名前付きの挨拶。nameが空なら 'world' になります。"""
    return f"Hello, {name or 'world'}!"
Python
# tests/test_calculator.py
# いくつかの関数だけテストして、あえて未実行の行を残します。

import pytest
from app.calculator import add, divide, safe_divide, greet

def test_add():
    # 基本的な加算
    assert add(2, 3) == 5

def test_divide_ok():
    # 通常の割り算
    assert divide(10, 2) == 5

def test_divide_zero():
    # 0除算で例外が発生することを確認
    with pytest.raises(ZeroDivisionError):
        divide(1, 0)

def test_safe_divide_default_is_none():
    # default未指定の場合の0除算はNone
    assert safe_divide(1, 0) is None

# greetのデフォルト分岐や safe_divide の default 指定分岐はあえて未テストにしておきます

最小のカバレッジ計測は次のコマンドです。

Shell
pytest --cov

しかし、これだと対象が広すぎることがあるため、測定対象を明示するのが基本です。

Shell
pytest --cov=app

実行例(ターミナル出力)

text
============================= test session starts =============================
collected 4 items

tests/test_calculator.py ....                                           [100%]

---------- coverage: platform linux, python 3.11.9-final-0 -----------
Name                  Stmts   Miss  Cover
-----------------------------------------
app/calculator.py        20      3    85%
-----------------------------------------
TOTAL                    20      3    85%

============================== 4 passed in 0.10s =============================

対象モジュールを指定する(–cov=パッケージ名)

–cov=で対象を指定すると、その配下のPythonファイルが集計されます。

複数指定も可能です。

Shell
# 単一パッケージ
pytest --cov=app

# 複数パッケージ(例: app と utils の両方)
pytest --cov=app --cov=utils

プロジェクトルートで実行すると、相対パスの解決やインポートが安定します。

testsディレクトリの中でpytestを実行すると、パスやインポートの不整合で0%になることがあるため注意してください。

ターミナル出力(coverage)の読み方

上の例に加えて--cov-report=term-missingを付けると、未実行の行番号が表示されて改善点が明確になります。

Shell
pytest --cov=app --cov-report=term-missing
実行結果
---------- coverage: platform linux, python 3.11.9-final-0 -----------
Name                  Stmts   Miss  Cover   Missing
---------------------------------------------------
app/calculator.py        20      3    85%   16, 20-21
---------------------------------------------------
TOTAL                    20      3    85%
  • Name: ファイル名やモジュール名です。
  • Stmts: 実行対象の文数です。
  • Miss: 実行されなかった文の数です。
  • Cover: 行カバレッジの割合(%)です。
  • Missing: 未実行の行番号の一覧です。範囲表示(20-21)は連続行を意味します。

分岐の網羅性も見たい場合は--cov-branchを付けます。

出力にBranchなどの列が追加され、条件分岐のカバレッジを確認できます。

Shell
pytest --cov=app --cov-branch --cov-report=term-missing

HTMLレポートの出力と見方

HTMLレポートを生成する(–cov-report=html)

HTMLレポートは未実行行が色分けされ、ブラウザで直感的に確認できます。

テキスト出力と併せて生成するのがおすすめです。

Shell
# ターミナル出力とHTMLレポートを同時に生成
pytest --cov=app --cov-report=term-missing --cov-report=html

標準ではhtmlcovというディレクトリにレポートが生成されます。

タイトルやディレクトリは.coveragercで変更できます(後述)。

出力先(htmlcov)を開く手順

生成後、以下のいずれかの方法でhtmlcov/index.htmlを開きます。

  • macOS: open htmlcov/index.html
  • Linux: xdg-open htmlcov/index.html
  • Windows: start htmlcov\index.html
  • どの環境でも使える方法: 簡易HTTPサーバで配信して開く
Shell
# プロジェクトルートで実行
python -m http.server 8000
# ブラウザで http://localhost:8000/htmlcov/index.html を開く

HTMLレポートの色と数値の見方

ファイル一覧では、各ファイルのカバレッジがパーセンテージと色で表示されます。

一般的にカバレッジが高いほど緑、低いほど赤に近い色になります。

デフォルトのしきい値は概ね高カバレッジ90%低カバレッジ50%付近で色分けされます。

ファイルをクリックすると、#で未実行行にマーカーが付き、上下文を確認しながらどのテストを追加すべきか判断できます。

以下は、よく使う出力オプションのまとめです。

オプション目的
--cov=PACKAGE測定対象のソース指定--cov=app
--cov-branch分岐カバレッジも計測--cov=app --cov-branch
--cov-report=term-missing未実行行の行番号を表示--cov-report=term-missing
--cov-report=htmlHTMLレポートを生成--cov-report=html
--cov-fail-under=NUM規定値未満でテスト失敗にする--cov-fail-under=90

便利なオプションとつまずき対策

最低カバレッジを設定する(–cov-fail-under=数値)

継続的インテグレーション(CI)で一定の品質を担保したい場合、--cov-fail-underが便利です。

指定値を下回るとpytestが失敗扱い(非ゼロ終了コード)になります。

Shell
pytest --cov=app --cov-report=term-missing --cov-fail-under=90

実行例(しきい値未達で失敗)

text
---------- coverage: platform linux, python 3.11.9-final-0 -----------
Name                  Stmts   Miss  Cover   Missing
---------------------------------------------------
app/calculator.py        20      3    85%   16, 20-21
---------------------------------------------------
TOTAL                    20      3    85%

FAILED Required test coverage of 90% not reached. Total coverage: 85.00%

PRにこの条件を組み込むと、レビュー時にカバレッジ低下を自動で検出できます。

テスト対象を限定する(複数の–cov指定)

大きなリポジトリでは対象を限定すると解析が速くなります。

複数の--covを並べて、必要なパッケージだけを測りましょう。

Shell
# アプリケーション本体とユーティリティを測る
pytest --cov=app --cov=utils --cov-report=term-missing

サイトパッケージなど外部ライブラリは原則測らないのが実務的です。

必要なら.coveragercomitを設定して除外できます。

INI
# .coveragerc の例
[run]
# 必要に応じて src レイアウトなどのパスを明示
# source = app

[report]
# レポートから tests 配下を除外
omit =
    tests/*
    */site-packages/*

# 欲しければ分岐カバレッジを常に有効化
# precision などの出力調整も可能
# show_missing = True

[html]
# HTMLの出力先やタイトル
directory = htmlcov
title = Project Coverage Report

よくあるつまずき(0%になる/対象外になる)

初心者が遭遇しやすいポイントを具体的に解説します。

1. –covの対象を間違えている

–covに誤ったパスやパッケージ名を指定すると、測定対象に含まれず0%になったり、何も表示されなかったりします。

常にプロジェクトルートでpytest --cov=appのように実行し、パッケージ名はimportに使う名前と一致させましょう。

2. srcレイアウトでインポートできていない

プロジェクトが以下のようなsrcレイアウトの場合、テスト実行時にパッケージがインポートできず、結果として実行されないことがあります。

text
your_project/
├─ src/
│  └─ app/
│     ├─ __init__.py
│     └─ calculator.py
└─ tests/
   └─ test_calculator.py

対策はどちらかです。

  • pip install -e .で編集可能インストールを行い、appをインポート可能にする。
  • 一時的にPYTHONPATH=srcを設定してpytestを実行する。
  • --cov=src/appと指定しつつ、インポート経路も上記のいずれかで解決する。

3. 実行されていない行を見逃している

--cov-report=term-missingやHTMLレポートでどの行が実行されていないかを確認しましょう。

未実行行に対応するテストを追加すると、カバレッジが意味のある形で向上します。

例えば、先ほどの例ではgreet(None)safe_divide(1, 0, default=0)の分岐が未実行でした。

Python
# tests/test_calculator_more.py
# 未実行だった分岐を補う例です。

from app.calculator import greet, safe_divide

def test_greet_default():
    # name が falsy の場合の分岐を実行
    assert greet("") == "Hello, world!"

def test_safe_divide_with_default():
    # default を指定した 0 除算の分岐を実行
    assert safe_divide(1, 0, default=0) == 0

4. 並列実行やサブプロセスで集計できない

マルチプロセスやサブプロセスを伴うコードでは、カバレッジ収集が分散してしまうことがあります。

pytest-covは多くの場合自動で子プロセスも計測しますが、うまくいかない場合は.coveragercで以下の設定を検討します。

INI
# .coveragerc の例(サブプロセス対応を強化)
[run]
concurrency = multiprocessing
parallel = True

実行後にcoverage combineで結果を統合するアプローチもありますが、まずは単純なケースから動作確認するのが安全です。

5. 除外設定(omit/exclude)に引っかかっている

.coveragercomitexclude_linesが強すぎると、意図せず対象外になります。

設定を最小限にして原因を切り分け、必要に応じて徐々に広げる方が失敗しにくいです。

まとめ

テストカバレッジは、「どこをテストしていないか」を可視化するための実践的な道具です。

pytest-covを使えば、pytestに数個のオプションを足すだけで、ターミナルとHTMLの両方で結果を確認できます。

運用のコツは、--cov=パッケージ名で対象を明確化し、--cov-report=term-missingで未実行行を把握し、必要なテストをピンポイントに追加していくことです。

しきい値は--cov-fail-underでルール化しつつ、数字のためのテストではなく、バグを防ぐためのテストを意識してください。

HTMLレポートを定期的に見直し、プロジェクトの成長に合わせて設定(.coveragerc)を育てていけば、テストの網羅性と開発速度の両立に近づけます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!