Pytestを利用したPythonのユニットテスト
最近ちょっと忙しくなってきて、ブログの更新頻度が減ってきてたので、ぼちぼち更新していこうかなと。。。
ということで、テスト関連で少し記載していきます。
今まで、Pythonのテストとしては、組み込みの unittest を利用することが多かったのですが、最近 pytest を触れる機会があったので、そちらに関して記載して行こうと思います。
Pytestとは
Pythonのテスティングフレームワークで、小さくて簡単なテストから、複雑なテストまでサポートをしてくれるようです。
pytest: helps you write better programs — pytest documentation
インストール
pip install pytest
使い方
pytest コマンドで、ファイル名の先頭が test_で始まるファイル(デフォルト設定)内の、先頭がtest_で始まる関数(メソッド)をテスト対象として、テストを実行します。
assert文を利用し、結果がFAILのものを出力してくれます。
def inc(x): return x + 1 def test_answer(): assert inc(1) == 2 assert inc(2) == 2
pytest
============================================================================================================ test session starts =============================================================================================================
platform darwin -- Python 3.6.1, pytest-3.6.2, py-1.5.3, pluggy-0.6.0
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_sample.py F [100%]
================================================================================================================== FAILURES ==================================================================================================================
________________________________________________________________________________________________________________ test_answer _________________________________________________________________________________________________________________
def test_answer():
assert inc(1) == 2
> assert inc(2) == 2
E assert 3 == 2
E + where 3 = inc(2)
test_sample.py:9: AssertionError
========================================================================================================== 1 failed in 0.14 seconds ==========================================================================================================
assert文について
assertの条件に満たないものについて、AssertionError を発生させます。
assert 条件, メッセージ
詳しくは、以下の記事が参考になりました。
クラスベース
テストケースをクラスごとに、グルーピングすることが可能です。
class TestClass(object): def test_one(self): x = "this" assert 'h' in x def test_two(self): x = "hello" assert hasattr(x, 'check')
fixture
pytestにはfixtureという機能があり、これを利用することで、繰り返し実行するケースや、テストの前後処理等、様々な場面で活用することが出来ます。
import pytest @pytest.fixture def user_api_mock(): return { 'first_name': 'Taro', 'last_name': 'Tanaka', 'age': 32 } def test_fullname(user_api_mock): assert user_api_mock['first_name'] + user_api_mock['last_name'] == 'TaroTanaka'
setup/teardown
unittestの setUp、tearDownに相当する機能です。
- Moduleレベル
def setup_module(module): """ モジュールテスト実行の前処理 """ def teardown_module(module): """ モジュールテスト実行の後処理 """
- Classレベル
class TestClass(object): @classmethod def setup_class(self): """ テストclass実行の前処理 """ @classmethod def teardown_class(self): """ テストclass実行の後処理 """
設定
実行対象のディレクトリ以下に、conftest.pyファイル名で、pytestの設定を変えることが出来ます。
- 例: pytestに引数を追加する
import pytest # pytest_plugins = 'plugin_name' # pluginの追加も可能 def pytest_addoption(parser): parser.addoption('--target', default='unit', dest='target', help='Target test type (all|e2e|unit)') def pytest_configure(config): config.addinivalue_line('markers', 'target(name): Target test type name.') def pytest_runtest_setup(item): target = [mark.args[0] for mark in item.iter_markers(name='target')] if target: if item.config.getoption('--target') not in target: pytest.skip('test require target in %r' % target)
pytest --help ... custom options: --target=TARGET Target test type (all|e2e|unit)
プラグイン
よく使うプラグインをいくつか紹介です。
Good Integration Practices
公式で紹介されている、Good Integration Practicesの解説をかいつまんでみました。
- ディレクトリ構造
Pythonのパッケージ開発の構造。他にもいくつかありますが、とりあえず、ここでは1パッケージ単位で解説します。
setup.py
mypkg/
__init__.py
app.py
view.py
tests/
test_app.py
test_view.py
- setup.py
pytest-runnerプラグインを使用して、テスト実行をsetuptoolsベースのプロジェクトに統合することができます。
from setuptools import setup setup( # ..., setup_requires=["pytest-runner", ...], tests_require=["pytest", ...], # ここで予めplugin入れてもok # ..., )
- setup.cfg
aliasesとしてpytestを指定します。
[aliases] test=pytest
pytestの設定も指定することが出来ます。
[tool:pytest]
addopts = --verbose --cov cchan_web --cov-report html --cov-config .coveragerc
python_files = tests/*/test_*.py
norecursedirs =
.git
.tox
.env
venv
dist
build
south_migrations
migrations
example
.coveragercで pytest-covの設定が指定できます。
- 実行
python setup.py test