サーバーエンジニアの原です。
今回は、Python製テスティングフレームワークpy.testの数あるプラグインのうち、おすすめプラグインをご紹介します。
Python 3.4、pytest 2.7.0を前提とします。
pytest-flakes
pytest-flakesは、Pythonの文法/コードスタイルチェッカーであるpyflakesをテスト時に実行できるようになるプラグインです。
例えばこのような(全く役に立たない)テストコードがあったとします。
# -*- coding: utf-8 -*- def test(): a = 5 assert 1+2 == 3
これを--flakesオプションを付けてテストを実行すると、未使用の変数があるため、テストが失敗します。
$ py.test --flakes ===================================== test session starts ============================== platform darwin -- Python 3.4.2 -- py-1.4.27 -- pytest-2.7.1 rootdir: /Users/hara/work/pytest, inifile: plugins: cache, flakes collected 2 items tests/test_app.py F. ========================================== FAILURES ==================================== _______________________________________ pyflakes-check _________________________________ /Users/hara/work/pytest/tests/test_app.py:5: UnusedVariable local variable 'a' is assigned to but never used ============================= 1 failed, 1 passed in 0.02 seconds =======================
これにより、CIでコードスタイルもチェックできるようになります。
特定のスタイルチェックを無効化したり、特定のファイルのみにスタイルチェックを実行するなどの設定もできるので、プロジェクトの特性に応じて設定しておくとよいでしょう。
pytest-echo
pytest-echoは、テスト実行時に環境変数やパッケージのバージョンなどを出力するプラグインです。
以下のようなオプションを付けて実行すると、テスト結果に環境変数やパッケージのバージョンなどが含まれるようになります。
$ py.test --echo-env PWD --echo-version pip --echo-version pytest ================================= test session starts ================================== platform darwin -- Python 3.4.2 -- py-1.4.27 -- pytest-2.7.1 Environment: PWD: /Users/hara/work/pytest Package version: pip: 1.5.6 pytest: 2.7.1 rootdir: /Users/hara/work/pytest, inifile: plugins: cache, cov, echo, flakes collected 1 items tests/test_app.py . =============================== 1 passed in 0.02 seconds ===============================
テスト実行環境の情報を出力しておくことで、テスト失敗時の原因追求がしやすくなります。
引数が多くなってしまう場合は、以下のようにpytest.iniのaddoptsに予めオプションを指定しておくと毎回オプションを指定する必要がなくなります。
addopts = --echo-env PWD --echo-version pip --echo-version pytest
pytest-cov
pytest-covは、テスト実行時にテストカバレッジを取得するプラグインです。
--covオプションの後ろには、カバレッジを取得する対象ディレクトリを指定します。
$ py.test tests --cov . ================================= test session starts ================================== platform darwin -- Python 3.4.2 -- py-1.4.27 -- pytest-2.7.1 rootdir: /Users/hara/work/pytest/tests, inifile: plugins: cache, cov, echo, flakes collected 1 items tests/test_app.py . ------------------- coverage: platform darwin, python 3.4.2-final-0 -------------------- Name Stmts Miss Cover ------------------------------------ sample 2 2 0% tests/test_app 3 0 100% ------------------------------------ TOTAL 5 2 60% =============================== 1 passed in 0.03 seconds ===============================
テストの実行結果には影響を与えませんが、テストカバレッジを手軽に取得することができます。
pytest-describe
pytest-describeは、RSpecやJasmineのようなDescribeスタイルと呼ばれるテストコード記法をサポートするプラグインです。
py.testにはクラスを使用することで複数のテスト関数(メソッド)をまとめることができますが、そのクラスにはTestというプレフィックスを付けなければならなかったり、テスト関数(メソッド)ごとにselfを引数に取る必要があったりとスマートに記述することができませんでした。
pytest-describeを使用することで複数のテスト関数を関数でまとめることができるため、特別なルールなしに記述することが可能となっています。
以下に一例を載せます(READMEからの引用です)。
# -*- coding: utf-8 -*- import pytest def describe_list(): @pytest.fixture def list(): return [] def describe_append(): def adds_to_end_of_list(list): list.append('foo') list.append('bar') assert list == ['foo', 'bar'] def describe_remove(): @pytest.fixture def list(): return ['foo', 'bar'] def removes_item_from_list(list): list.remove('foo') assert list == ['bar']
以下のようなテスト結果になります。
$ py.test -v ================================= test session starts ================================== platform darwin -- Python 3.4.2 -- py-1.4.27 -- pytest-2.7.1 -- /Users/hara/.pyenv/versions/engineer_blog/bin/python3.4 cachedir: /Users/hara/work/pytest/.cache rootdir: /Users/hara/work/pytest, inifile: plugins: cache, cov, describe, echo, flakes collected 2 items tests/test_list.py::describe_list::describe_append::adds_to_end_of_list PASSED tests/test_list.py::describe_list::describe_remove::removes_item_from_list PASSED =============================== 2 passed in 0.02 seconds ===============================
describeというプレフィックスの関数が、テストをまとめる関数であることを表しています。
このプレフィックスは、pytest.iniにdescribe_prefixesという設定を追加することで自分の好きなように修正することができます。
まとめ
4点のpy.testプラグインをご紹介しました。
Pythonを初めとするLLの良さの一つとして、コンパイルという手順が無いことによるユニットテスト等のフィードバックループの回しやすさが挙げることができます。LLの力を最大限に活かし、より良いユニットテストを行なうためにも、テスト手法の改善に努めていきたいものです。
py.testには他にもプラグインがたくさんあります。こちらにプラグイン一覧がありますので、興味がある方は調べてみてください。