【Python】テストカバレッジを計測する方法(pytest-cov)

Python

こんにちは、かつコーチです。

テストを書き始めると、次に気になるのがこの疑問です。

「自分のコード、どこまでテストできているんだろう?」

感覚だけで「たぶん大丈夫」と判断してしまうと、テストしていない部分に潜むバグを見逃しがちです。

この記事では、コードのどこがテストされているかを数値化するpytest-covの使い方を解説します。

インストール方法から、カバレッジレポートの読み方、そして「100%を目指しすぎない」考え方まで紹介します。

読み終える頃には、テストの抜け漏れを客観的に把握できるようになります。

pytest-covとは?

テストカバレッジとは

テストカバレッジとは、コード全体のうち、テストによって実行された行の割合のことです。

例えば100行のコードのうち80行がテストで実行されていれば、カバレッジは80%になります。

数値化することで、「なんとなくテストした気になっている」状態を防げます。

pytest-covとは

pytest-covは、pytestにカバレッジ計測機能を追加するプラグインです。

内部的にはcoverage.pyというライブラリを使っており、pytestコマンドにオプションを1つ足すだけで計測できます。

カバレッジ計測の手順

手順1:pytest-covをインストールする

pip install pytest-cov

手順2:テスト対象のコードを用意する

割引価格を計算する関数を例にします。

わざと分岐を複数入れて、カバレッジの違いが分かりやすいようにしています。

# discount.py
def calc_discount_price(price, member_rank="normal"):
    """会員ランクに応じた割引価格を計算する"""
    if price < 0:
        raise ValueError("価格は0以上である必要があります")

    if member_rank == "gold":
        return int(price * 0.8)
    elif member_rank == "silver":
        return int(price * 0.9)
    else:
        return price

手順3:一部のケースだけテストを書く

あえて、goldランクのケースだけテストを書いてみます。

# test_discount.py
from discount import calc_discount_price


def test_gold_member():
    assert calc_discount_price(1000, "gold") == 800

手順4:カバレッジ付きでテストを実行する

--covオプションで、計測対象のモジュールを指定します。

pytest --cov=discount test_discount.py

実行すると、次のようなレポートが表示されます。

Name           Stmts   Miss  Cover
----------------------------------
discount.py        8      3    62%
----------------------------------
TOTAL               8      3    62%

カバレッジレポートの読み方

  • Stmts:計測対象の実行可能な行数
  • Miss:一度もテストで実行されなかった行数
  • Cover:実行された割合(Stmts中、Missを除いた割合)

Coverが62%ということは、silverランクやnormalランク、価格が負の場合の分岐が、まだテストで通っていないことを意味します。

どの行が未テストかを詳しく見る

--cov-report=term-missingを付けると、未実行の行番号まで表示されます。

pytest --cov=discount --cov-report=term-missing test_discount.py
Name           Stmts   Miss  Cover   Missing
--------------------------------------------
discount.py        8      3    62%   4, 8, 10
--------------------------------------------
TOTAL               8      3    62%

Missingの行番号を見れば、どの分岐に手を付ければよいかが一目で分かります。

カバレッジ100%を目指しすぎない考え方

カバレッジは「品質」そのものではない

カバレッジ100%は、あくまで「すべての行が一度は実行された」ことを示すに過ぎません。

assertを書かず関数を呼ぶだけでもカバレッジは上がってしまうため、100%でもバグが潜んでいる可能性はあります。

優先すべきは「重要なロジックの分岐」

すべての行を均等に狙うより、金額計算やエラー処理など、間違えると影響が大きい部分を優先してテストするほうが効果的です。

目安としては、70〜85%程度のカバレッジを維持しつつ、重要なロジックは個別に丁寧にテストする、というバランスがおすすめです。

よくあるつまずきポイント・エラー対処

–cov対象の指定漏れでカバレッジが計測されない

筆者が実際に経験したのが、--covにモジュール名を指定し忘れたケースです。

❌ Before(正しく計測されない書き方)

pytest --cov test_discount.py

実行すると、次のような結果になりました。

Name           Stmts   Miss  Cover
----------------------------------
discount.py        8      3    62%
test_discount.py   3      0   100%
----------------------------------
TOTAL              11      3    73%

一見動いているように見えますが、test_discount.py自体までカバレッジ対象に含まれてしまい、本来知りたいdiscount.pyの数値がノイズに埋もれていました。

✅ After(対象を絞った書き方)

pytest --cov=discount test_discount.py
Name           Stmts   Miss  Cover
----------------------------------
discount.py        8      3    62%
----------------------------------
TOTAL               8      3    62%

--cov=discountのように対象モジュール名を明示することで、テストコード自体を除いた、本来知りたい数値だけが表示されます。

計測対象を絞らないと、テストコードの行数がカバレッジ全体の数値を底上げしてしまう点に注意しましょう。

まとめ

この記事のポイント

  • テストカバレッジは、コードのうちテストで実行された行の割合を示す指標
  • pip install pytest-covでインストールし、--cov=モジュール名で計測する
  • --cov-report=term-missingで、未テストの行番号まで確認できる
  • カバレッジ100%は品質を保証するものではない
  • 重要なロジックを優先しつつ、70〜85%程度を目安にするのが現実的

次に読むべき記事

  • pytestの基本:テストの書き方入門
  • unittestとpytestの違い・使い分け
  • モックを使ったテストの書き方(unittest.mock)

タグ: Python, 中級者向け, テスト

タイトルとURLをコピーしました