Python プロジェクトでユニットテストを実行する pytest を導入しカバレッジレポートを出力する
Python プロジェクトでユニットテストを行うため、pytest というツールを導入してみた。
目次
Python 用のユニットテストツール
Python には unittest という UT 用のモジュールが標準で搭載されていて、コレを使ってもユニットテストが簡単に行える。
しかし、複数のテストファイルの一括実行や、カバレッジレポートの出力が若干面倒臭そう (coverage
モジュールを併用する) だったので、今回はテストランナーとして pytest を採用し、カバレッジレポート生成に pytest-cov を使用することにした。
ちなみに、Scrapy の Spider もテストしたいなぁーと思ったのだが、コチラは Scrapy が持っている Contracts という機能を使うと、簡単にテストできるらしいので、コレでいいかな。
- 参考 : ScrapyでSpiderのテストを書く - Qiita
- 参考 : scrapyのspiderのテスト(scrapy check / contract) - Dd enzow(ill)? with DB and Python
pipenv でモジュールをインストールする
というワケで早速インストールしていこう。
$ pipenv install --dev pytest pytest-cov
コレだけ。
テストコードを書く
今回のプロジェクトは次のような構成とする。
example-project/
├ src/ … テストしたい既存コード
│ ├ __init__.py
│ └ my_example.py
└ tests/ … 今回新たに作るディレクトリ
└ __init__.py
└ test_my_example.py
テスト対象コードは ./src/
ディレクトリ配下にあるテイとし、./src/
と同じ階層に ./tests/
ディレクトリを作る。
./tests/
配下には、空ファイルの __init__.py
を作るのと、test_
から始まるテストコードを作る。pytest は tests
ディレクトリや test_
から始まるファイルを自動的に特定して実行してくれるのだ。
空の ./tests/__init__.py
というファイルがなぜ必要かというと、import
におけるパス解決が上手く出来ず、以下のようなエラーが出るため。
ImportError: attempted relative import with no known parent package
./tests/__init__.py
を用意することで、上手くモジュールと認識されるようになる。
テスト対象コードは次のようなモノをサンプルで用意した。
./src/my_example.py
class MyExample():
def for_unit_test():
return 1
ただ 1
を返すだけの関数を持つクラスだ。
テストコードは次のような要領で書く。
./tests/test_my_example.py
# テスト対象クラスを import する
from src.my_example import MyExample
# 成功するテストケース
def test_for_unit_test_01():
assert MyExample.for_unit_test() == 1
# わざと失敗するテストケースも用意した
def test_for_unit_test_02():
assert MyExample.for_unit_test() == 2
実行してみる
とりあえず実行するなら次のように実行すれば良い。
$ pipenv shell
$ pytest
2件のテストケースが実行され、1件成功・1件失敗であることが分かるだろう。
ケース別にテスト状況を出力するなら、次のようにする。
$ pytest -v
pytest-cov を組み合わせて HTML 形式のカバレッジレポートを出力するには、次のように実行する。
$ pytest --cov=src --cov-report=html
--cov
オプション引数でカバレッジレポートを取るディレクトリを指定し、--cov-report=html
で HTML 形式で出力するよう設定している。
Pipfile で指定するなら次のようにすれば良い。
[scripts]
test = "pytest --cov=tickets --cov-report=html"
コレで pipenv run test
と実行できるようになる。
HTML 形式のカバレッジレポートは ./htmlcov/index.html
を開くと確認できる。見た目は Angular などに組み込まれている Istanbul Reporter に似ていて、分かりやすい。
テストを実行すると .coverage
というファイルも生成されるので、以下2つは .gitignore
で管理するようにしておこう。
# .gitignore
htmlcov/
.coverage
以上
pytest を使うとユニットテストの一括実行ができ、pytest-cov を組み合わせれば HTML 形式でのカバレッジレポートが簡単に出力できることが分かった。