この記事はPython その2 Advent Calendar 2015の23日目の記事です。
Djangoでカバレッジを測定する
Djangoでユニットテストのカバレッジを計測するには、django-noseを使うのが定番です。
設定の仕方はちょっと検索すれば、たくさん情報が出てくるのでここでは再掲はしません。Qiita上の記事だと、以下の記事がDjango 1.9がリリースされた現在でも通用します。
試しにこのミニマムなDjangoアプリケーションにdjango-nose
を使うように設定して、カバレッジを計測してみます。
$ ./manage.py test sample --with-coverage --cover-package=sample --cover-html
nosetests sample --with-coverage --cover-package=sample --cover-html --verbosity=1
Creating test database for alias 'default'...
.
Name Stmts Miss Cover Missing
--------------------------------------------------
sample.py 0 0 100%
sample/settings.py 21 9 57% 58, 76, 112-130
sample/urls.py 4 0 100%
sample/views.py 5 0 100%
--------------------------------------------------
TOTAL 30 9 70%
----------------------------------------------------------------------
Ran 1 test in 0.011s
OK
Destroying test database for alias 'default'...
Coverage.pyでカバレッジを計測する
ほとんどの場合django-noseを使えば問題ないはずですが、現時点で最新版のdjango-nose==1.4.2
ではDjango 1.8の新機能に追いついていない点があるのが気になっています。
またカバレッジを出力しやすいということ以外はdjango-noseの利点を感じにくくなってきたので、Djangoの標準のテストランナーでもいいやという気も強くなってきています。
このstackoverflowの投稿によると、Coverage.pyを直接使ってカバレッジを計測することもできるようなので、自分で試してみました。
先ほどのサンプルDjangoアプリケーションでは、こちらのリビジョンになります。
カバレッジを計測しつつテストを実行。
$ coverage run --source=sample --omit='*/tests/*' manage.py test sample
カバレッジレポートを出力。
$ coverage report
Name Stmts Miss Cover
----------------------------------------
sample/__init__.py 0 0 100%
sample/settings.py 20 0 100%
sample/urls.py 4 0 100%
sample/views.py 5 0 100%
sample/wsgi.py 4 4 0%
----------------------------------------
TOTAL 33 4 88%
カバレッジレポートをHTMLでcover
ディレクトリに出力。
$ coverage html --directory=cover
django-noseのカバレッジ計測機能もCoverage.pyをラップしただけなので、コンソール上のレポートもHTMLレポートもほとんど出力は同じです。
ワーキングディレクトリに.coveragerc
を定義しておけば、上記のコマンドのオプションを省略可能です。
[run]
omit = */tests/*
[html]
directory = cover
実行例。
$ coverage run --source=sample manage.py test sample
$ coverage report
$ coverage html
.coveragerc
についてはドキュメントを参照。
最後に
django-noseではなく、Coverage.pyでカバレッジを計測する例を紹介しました。
django-noseなしだと3回コマンドを実行しないと実現できないことが、django-noseでは1回で出来るので便利なことは間違いないですが、CIでうまく自動化してしまえば、Coverage.pyだけでやるというのも選択肢としてはありですね。