今川館

都内勤務の地味OLです

coverage combineコマンドで複数の集計結果を結合する

カバレッジ(網羅率)とは?

カバレッジとはテストコードがどれだけテスト対象の内容を網羅しているかを表す割合です。

例えば、以下のファイルにはfoo, bar, bazという3つの関数が定義されていますが、これらのすべての内容をテストで実行済みであればカバレッジは100%となります。

# -*- coding:utf-8 -*-


def foo():
    return 1


def bar():
    return 2


def baz(x):
    if x < 5:
        return 3
    else:
        return 4

本当はカバレッジは3種類の評価基準があってそれぞれ評価の仕方が違うのですが、ここではその詳細な説明は割愛します。

Pythonのcoverageモジュール

Pythonカバレッジを取得するときはcoverageというモジュールを使います。

$ easy_install coverage

インストールするとcoverageというコマンドが利用可能になります。
このコマンドを使ってカバレッジをhtml形式で出力したレポートが以下の図です。

こんな風に、テストで網羅されていない部分は赤くなります。

coverageコマンドの基礎: 集計と出力の2ステップ構成

coverageコマンドは「データの集計」と「レポートの出力」という2つのステップに手順が分けられています。

データの集計: coverage run

カバレッジデータの集計はcoverage runというサブコマンドで行います。

$ coverage run test_sample.py

こんな風にすると、カレントディレクトリに.coverageというファイルができます。
これがカバレッジのデータファイルです。

レポートの出力: coverage report/html/xml

レポートの出力は出力形式の違う3種類のサブコマンド(以下)があるので、好きなものを選んで実行します。

  • プレーンテキスト : reportコマンド
  • html形式 : htmlコマンド
  • xml形式 : xmlコマンド

さっき示した図は

$ coverage html

というように、coverage htmlコマンドで出力したものです。

複数のデータファイルを結合するcoverage combineコマンド

ここまでが基本ですが、カバレッジのデータファイルは複数のファイルを結合することができます。
それがcombineコマンドです。
これはすぐれもので、あるモジュールの中の異なる関数同士の網羅率を結合してくれるだけでなく、同じ関数の中の一部の網羅率もちゃんと結合してくれます。
口で言うと判りにくいので、実際に例を示します。

combineの利用例

coverage combineの利用例
今回のサンプルコードを上記に上げておきました。
これを使ってcombineコマンドの使い方を解説します。

最初の状態ではsample.pyのテストを二つのファイルに分けておきます。
図のように、test_sample.py, test_sample2.pyの両方を実行するとsample.pyのカバレッジは100%になります。


(py27)oyakata@ubuntu:~/Documents/bplt0216$ ls
sample.py  test_sample2.py  test_sample.py

test_sample.pyを実行して生成された.coverageをリネームしておきます。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ coverage run test_sample.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
(py27)oyakata@ubuntu:~/Documents/bplt0216$ mv .coverage .coverage.1

test_sample2.pyも実行してリネームします。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ coverage run test_sample2.py 
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
(py27)oyakata@ubuntu:~/Documents/bplt0216$ mv .coverage .coverage.2

ここまで進めるとカバレッジのデータファイルは以下の通り二つ存在するようになります。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ ls -a
.  ..  .coverage.1  .coverage.2  sample.py  sample.pyc  test_sample2.py  test_sample.py

データファイルを結合します。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ coverage combine

結合の結果、二つに分かれていたデータファイルがひとつの.coverageになります。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ ls -a
.  ..  .coverage  sample.py  sample.pyc  test_sample2.py  test_sample.py

これをもとにhtml形式でレポートを出力すると100%になることが判ります。

(py27)oyakata@ubuntu:~/Documents/bplt0216$ coverage html
(py27)oyakata@ubuntu:~/Documents/bplt0216$ ls
htmlcov  sample.py  sample.pyc  test_sample2.py  test_sample.py

用途

combineの用途としてわたしが思いつくものを二つ考えました。
一つは、複数のサーバーに分散してテストを実行した結果をまとめて集計するときです。
大量のテストをいちいちローカル端末で実行するのは時間がかかるので開発サーバーその他に分散して結果だけ一カ所にまとめるという方法です。
Jenkinsを分散してテストを実行するなら特に有用でしょう。

もう一つは、大量のテストのカバレッジをちょっとずつ上げたいときです。
最初にすべてのカバレッジデータを集計しておいて、テストコードを少し書くたびにデータを結合して結果を確認するといったことができます。

いずれにせよ、テストの実行を一度に全部一括して行うのが嫌なときに役に立つコマンドであることは間違いないでしょう。

追記 2/17 coverage run --appendについて

coverage run --appendというのがあってこれもうまく使うと便利です。

1. 最初に全unittestを実行して .coverageを作っておく。
2. 自分がカバレッジを上げようとしているテストコードを増やす。
3. 2のテストコードだけを以下のコマンドで実行する(coverage run 追記モード)
$ coverage run --append python test_extra.py
4. coverage htmlを実行し、htmlレポートを再出力する。

自分が増やしたカバレッジが反映されていることを確認する。

$ coverage html
  • > ./htmlcovの下に出力されたレポートを見る。

この方法でやると、

  1. 毎度unittestを全部通さなくて良い。
  2. coverage combineより簡単な手順で作業できる。

というメリットがあるのでおすすめです。