2026年10月22日、Pythonのテストで広く使われているツールcoverage.pyの7.17.0が公開されました。coverage.pyは、テストを動かしたときに、コードのどの行や分岐が実際に実行されたかを測る道具です。
今回の版では、測った結果が実際と食い違う問題がいくつも直されています。あわせて、Python 3.10のサポートも終わりました。
テストをきちんと書いているつもりでも、測る道具が間違っていたら困りますよね。今回は、カバレッジの基本から始めて、何が直ったのかを実際に動かしながら見ていきます。
まずはカバレッジとは何か¶
最初に、カバレッジという言葉を確認しておきましょう。カバレッジは英語で覆う範囲という意味で、テストがコードのどれくらいを実行したかを割合で表したものです。
たとえばカバレッジが80%なら、コードの8割はテストで一度は動いたことになります。逆に言えば、残りの2割は一度も動かされないままということです。
行と分岐の2つの数え方¶
coverage.pyには、大きく分けて2つの数え方があります。違いを表にまとめます。
| 数え方 | 何を数えるか | 指定の仕方 |
|---|---|---|
| 行カバレッジ | 各行が1回でも実行されたか | 何も付けない |
| 分岐カバレッジ | ifなどの分かれ道で、両方の道を通ったか | --branchを付ける |
行カバレッジだけでは、見落としが出ることがあります。次の例で、その違いを確かめてみましょう。
実際に測ってみた¶
会員なら1割引きにしてから税込みの金額を返す、という小さな関数を用意しました。会員の場合だけを試しています。
def price_with_tax(price, member):
if member:
price = price * 0.9
return round(price * 1.1)
print(price_with_tax(1000, True))
coverage.py 7.17.0を入れた仮想環境で、手元のPython 3.11を使って測りました。まずはcoverage run shop.pyで動かし、coverage report -mで結果を表示します。
Name Stmts Miss Cover Missing
---------------------------------------
shop.py 5 0 100%
行カバレッジは100%です。すべての行が実行されたので、テストは完璧に見えますよね。
続いて、coverage run --branch shop.pyで分岐カバレッジも測りました。
Name Stmts Miss Branch BrPart Cover Missing
-----------------------------------------------------
shop.py 5 0 2 1 86% 2->4
今度は86%になりました。Missingの2->4は、2行目のifから、割引をせずに4行目へ進む道が一度も通られていない、という意味です。
つまり、会員でない人の計算は一度もテストされていないことが、分岐カバレッジならわかります。BrPartの列は、片方の道しか通らなかった分かれ道の数です。
テストそのものの書き方は、こちらで紹介しています。【関連記事】pytest入門|Pythonでテストを書く基本
7.17.0で何が変わったのか¶
では、今回のニュースの中身に入りましょう。coverage.pyの公式リポジトリにある変更履歴CHANGES.rstから、主な変更を表にまとめます。
| 分類 | 主な変更 |
|---|---|
| 対応範囲 | Python 3.10のサポートを終了、iOSとAndroid向けの配布物を追加 |
| 分岐の数え間違い | コメントや文字列の中の言葉で、分岐を誤って扱う問題を修正 |
| 分岐の数え間違い | withを3段以上重ねたときに、ありえない分岐が数えられる問題を修正 |
| データの消失 | 並列実行のデータが、まとめるときに消えることがある問題を修正 |
| 安全面 | ファイル名に含まれる制御文字を、報告の中で置き換えるように |
| 速度 | coverage reportの使うメモリを削減、HTMLの報告を約5%高速化 |
PyPIの記録によると、7.17.0が必要とするPythonは3.11以上です。ひとつ前の7.16.2は3.10以上だったので、3.10のままpip installすると、7.16系が入ることになります。
スマートフォン向けの配布物も加わった¶
変更履歴によると、7.17.0からiOSとAndroid向けにも、あらかじめビルドされた配布物が用意されました。PyPIを見ると、実際にandroidやiosという名前の付いたwheelファイルが並んでいます。
wheelとは、すぐにインストールできる形にまとめた配布用のファイルのことです。これにより、スマートフォンの上でも、C言語で書かれた速い計測の仕組みが使えるようになったと説明されています。
コメントの言葉で、分岐を数え間違えていた¶
初心者にも起こりうるのが、この問題です。変更履歴によると、コメントや文字列の中でif True:やwhile True:に触れただけで、その行の分岐が誤った扱いを受けることがありました。
なぜそんなことが起きるのか¶
while True:のような書き方は、条件が必ず真なので、ループを抜ける道は普通の形では通られません。そこでcoverage.pyは、こうした行を、片方の道しか通らなくて当然の分岐として特別扱いしています。
インストールされたcoverage.pyのコードを見比べると、この特別扱いの目印は、7.16.2では行のどこにあっても当てはまる書き方でした。7.17.0では、行の先頭にある場合だけ当てはまるように変わっています。
7.16.2と7.17.0で測り比べた¶
実際に試してみましょう。ifの行のコメントに、たまたまwhile True:という言葉を書いた関数を用意しました。
def greet(debug):
if debug: # while True: のような無限ループではない
print("debug mode")
return "hello"
print(greet(False))
7.16.2と7.17.0をそれぞれ新しい仮想環境に入れ、--branchを付けて測った結果です。
coverage.py 7.16.2
flag.py 5 1 2 0 86% 3
coverage.py 7.17.0
flag.py 5 1 2 1 71% 3
debugがTrueになる道は一度も通っていないので、本当は、片方しか通っていない分岐が1つあるはずです。ところが7.16.2では、コメントの言葉に反応して特別扱いされ、BrPartが0と数えられていました。
7.17.0では正しく1と数えられ、カバレッジは86%から71%に下がりました。コメントをデバッグ用という言葉に変えて7.16.2で測ると、71%になったので、コメントの中身だけで数字が変わっていたことになります。
Python 3.15.0でも同じコードを測ってみましたが、7.16.2は86%、7.17.0は71%と、結果は同じでした。
データが消えることがあった問題¶
もう1つ、実務で影響が大きそうなのが、並列実行のデータの問題です。coverage.pyには、複数のプロセスで別々に測ったデータを、あとから1つにまとめる仕組みがあります。
変更履歴によると、1つのデータファイルを複数回保存すると、ファイル名に入る識別用の値が、最初に保存したときのままになっていました。その結果、まとめる際にほかのファイルの重複だと見なされて削除され、最初の保存より後に記録したデータが失われることがあったそうです。
この問題は7.13.1から続いていたと書かれています。テストを並列で動かしてカバレッジを集めている方は、7.17.0に上げておくと安心です。
並列でまとめるときの基本の流れ¶
並列のデータは、次のような流れでまとめます。--parallel-modeを付けると、プロセスごとに別々のデータファイルが作られます。
coverage run --parallel-mode -m pytest
coverage combine
coverage report -m
coverage combineが、別々のファイルを1つにまとめる命令です。今回直ったのは、このまとめる段階でデータが消えてしまう問題でした。
ファイル名の制御文字と、そのほかの修正¶
安全面の修正も入っています。LinuxやmacOSのファイル名には、画面の色を変えたりカーソルを動かしたりする、制御文字と呼ばれる特別な文字を含められます。
変更履歴によると、こうした名前をそのまま報告に出すと、XMLの報告が壊れたり、ターミナルの表示を偽装されたりするおそれがありました。7.17.0では、報告の中で表示できない文字を置き換えるようになっています。
ほかにも、次のような修正が入っています。
| 修正 | 中身 |
|---|---|
| withの重ね書き | 3段以上重ねたwithで、ありえない分岐が数えられていた |
| XMLの報告 | 0%や100%に近いとき、line-rateの値がおかしくなっていた |
| エラーの文面 | データをまとめられないとき、どのファイルかを表示するように |
| C言語で書かれた計測部分 | フリースレッド版のPythonで安全でない参照の扱いを修正 |
フリースレッド版とは、GILと呼ばれる仕組みを外して、複数のスレッドを本当に同時に動かせるようにしたPythonのことです。
メモリの使いすぎも改善¶
変更履歴によると、coverage reportは、終わるまですべてのファイルの解析結果を持ち続けていました。大きなプロジェクトでは、7.14の10倍以上のメモリを使うことがあったそうです。
7.17.0では、表示に必要なものだけを持つように直されました。大きなプロジェクトでカバレッジの報告が重いと感じていた方には、嬉しい改善です。
上げる前にやっておきたいこと¶
最後に、coverage.pyを7.17.0へ上げる前に確かめておきたいことを整理します。
| 順番 | 確認すること |
|---|---|
| 1 | Python 3.11以上を使っているか |
| 2 | 分岐カバレッジの数字が下がっても慌てない |
| 3 | 下がったら、Missingの列でどの道が通られていないかを見る |
| 4 | カバレッジの最低ラインを決めている場合は、その値を見直す |
2番目は特に大事です。今回の修正で数字が下がるのは、測り間違いが直って本当の値に近づいたということで、テストが悪くなったわけではありません。
私は10年ほどエンジニアとして開発に関わってきましたが、ツールを上げた途端にカバレッジの最低ラインを割って、継続的インテグレーションが失敗したことが何度もあります。数字だけを見て慌てず、どの行や分岐が変わったのかを先に確かめるのが近道です。
以前、カバレッジ100%を目標にしたチームで、分岐を測っていなかったために、まさに先ほどの会員でない場合のような計算の不具合を見逃したことがあります。行だけでなく、--branchで分岐も測る習慣をおすすめします。
GitHub Actionsでテストとカバレッジの測定を自動化する方法は、こちらで紹介しています。【関連記事】GitHub Actions入門
主要なライブラリがPython 3.10を外していく流れについては、こちらでまとめました。【関連記事】Python 3.10のサポート終了から2週間、主要ライブラリの対応状況
まとめ¶
2026年10月22日、coverage.py 7.17.0が公開されました。コメントの言葉やwithの重ね書きによる分岐の数え間違い、並列実行のデータが消える問題などが直り、Python 3.10のサポートも終わっています。
上げたあとに数字が変わっても、それは正しく測れるようになった結果かもしれません。この機会に、--branchを付けて分岐のカバレッジも確かめてみてください。
ここまでお読みいただきありがとうございました。