Blanktar

  1. top
  2. blog
  3. 2015
  4. 08

pythonのdoctestのカバレッジを取る

しばらく前にunittestのカバレッジを取る方法を書きましたが、このとき使ったcoveragedoctestのカバレッジも取れるらしいです。 doctestについては簡単な解説記事がありますのでそちらもどうぞ。

まずはインストール。 pip/easy_installならcoverage、apt-getならpython-coverage-test-runnerのようですが試していません。 少なくともgentooではdev-python/coverageです。

インストール出来たら、テスト対象のソースを用意します。

def test(x):
    """ test function

    >>> test(10)
    'plus'
    >>> test(1)
    'plus'
    >>> test(-1)
    'minus'
    """

    if x > 0:
        return 'plus'
    elif x < 0:
        return 'minus'
    else:
        return 'zero'

今回はこんな感じで。test.pyとでもしておきましょうか。 一番最後のreturn 'zero'のところだけカバーされていないテストですね。

テスト実行用にソースコードの末尾に以下の三行を追加してきます。

if __name__ == '__main__':
    import doctest
    doctest.testmod()

こうすれば単純にソースを実行するだけでテストを実行できる。

準備が出来たら、テストを実行します。やり方はunittestの時と一緒。

$ coverage run test.py

問題なければ何も表示されません。

詳細を見たければ

$ coverage run test.py -v

とでもすると良いかも。

コンソールアプリケーションなどで追加した三行を入れるわけにはいかない場合。そんなときは、以下のようにしてテストを実行します。

$ coverage run -m doctest test.py

python -m doctest test.pyみたいな感じで分りやすくて良い。

テストが完了したら、以下のコマンドでレポートを出力。これもunittestと一緒です。というか全部一緒です。

$ coverage annotate test.py
$ cat test.py,cover
> def test(x):
>   """ test function

>   >>> test(10)
>   'plus'
>   >>> test(1)
>   'plus'
>   >>> test(-1)
>   'minus'
>   """

>   if x > 0:
>       return 'plus'
>   elif x < 0:
>       return 'minus'
!   else:
!       return 'zero'


> if __name__ == '__main__':
>   import doctest
>   doctest.testmod()

一行目のコマンドでレポートを吐かせて、二行目で内容を確認しています。 >で始まる行はテスト済み、!で始まる行は未テストです。 return 'zero'がテストされていないのが一目で…分かる、かも?

やっぱり見づらいので、HTML形式で出力しましょう。

$ coverage html test.py
$ xdg-open htmlcov/index.html

一行目でレポート出力、二行目でブラウザを開いて表示、です。 未テストのところに赤く色が付くのでかなり見やすい。

以下のようにするとカバレッジだけ表示されるので、てっとり早くそこだけ確認したい場合にどうぞ。

$ coverage report
Name    Stmts   Miss  Cover
---------------------------
test        9      1    89%

これだけ見たい場面ってのも少なそうな気がするけれど、どうなんだろう?

あと片づけは

$ coverage erase
$ *,cover
$ rm -r htmlcov

こんな感じで。若干面倒ですね。

こうやってカバレッジ取ってくれるととても楽しいのですが、楽しすぎてdoctestの方がソースより長くなったりして、うぅむ。 カバレッジ取ってまできちんとテストするときはunittest使うべきなんだろうなぁ…。

参考: ned / coverage.py / 課題 / #152 - can't get coverage to run doctests Bitbucket