従来のdoctest形式のテストをpytestフレームワーク内で統合実行する仕組みについて説明します。
doctest探索の設定
pytestはデフォルトでtest*.txtというパターンに一致するテキストファイルに対してdoctestを実行します。ファイル扩展子に応じてカスタマイズするには以下のように--doctest-globオプションを指定します:
pytest --doctest-glob='*.rst' --doctest-glob='*.md'
複数パターンを指定した場合、いずれかに合致するファイルがdoctest対象となります。
ファイルの文字エンコーディングを明示的に指定するには、pytest.iniでdoctest_encodingオプションを使います:
# pytest.ini
[pytest]
doctest_encoding = cp932
デフォルトはUTF-8です。
Pythonモジュール内のdocstringからのdoctest実行
Pythonの関数・クラス・モジュールdocstringに埋め込まれたコードブロックもdoctestとして実行可能です。--doctest-modulesオプション付きで実行すると、自動的に該当モジュールがスキャンされます:
pytest --doctest-modules
プロジェクト全体で常に有効化したい場合はpytest.iniに設定を保存できます:
# pytest.ini
[pytest]
addopts = --doctest-modules
例として:
# mymodule.py
def double(x):
"""数値を2倍します
>>> double(3)
6
"""
return x * 2
上記をpytestコマンドでチェック可能です。テスト發現数はファイル内のdoctestブロック数に応じて増加します。
doctestオプションの指定方法
doctestの実行振る舞いを調整するためのフラグは、--doctest-globや--doctest-modulesと同様にpytest.iniの設定として記述できます:
# pytest.ini
[pytest]
doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL REPORT_UDIFF
フラグの定義はPythonのdoctestモジュールの定数と一致します。以下はpytest独自拡張 denoteされた特別なオプションです:
ALLOW_UNICODE:出力中のu'...'と表記されるunicodeリテラルのプレフィクスuを無視しますALLOW_BYTES:バイト列のb'...'プレフィクスを比較時に無視します
また、doctestブロック単位でinlineで有効化も可能:
"""例
>>> get_message() # doctest: +ALLOW_UNICODE
'こんにちは'
"""
エラー発生時の挙動制御
デフォルトでは、失敗したdoctestブロックが見つかった時点で実行を中断します。すべてのdoctestブロックを実行し、結果を一括で表示させたい場合は以下のオプションを追加します:
pytest --doctest-modules --doctest-continue-on-failure
テスト名前空間の拡張
fixtureを通じてdoctestの実行環境へオブジェクトを注入できます。conftest.pyにfixtureを定義:
# conftest.py
import math
import pytest
@pytest.fixture(autouse=True)
def inject_math_tools(doctest_namespace):
doctest_namespace["math"] = math
この結果、docstring中で直接mathモジュールが利用可能です:
def calc_factorial():
"""階乗を求める
>>> math.factorial(5)
120
"""
return math.factorial(5)
出力レポート形式の変更
失敗時の差分表示形式は--doctest-reportオプションで制御できます:
pytest --doctest-modules --doctest-report udiff
pytest --doctest-modules --doctest-report cdiff
pytest --doctest-modules --doctest-report ndiff
pytest --doctest-modules --doctest-report only_first_failure
pytest --doctest-modules --doctest-report none
選択肢はdoctestレポーターの出力フォーマット指定子に対応しており、テスト結果の可読性向上に役立ちます。
テスト内でのfixture使用
doctestテキストファイル中でpytest fixtureを直接利用できます。たとえば、一時ディレクトリを使う場合:
>>> tmpdir = getfixture("tmpdir")
>>> f = tmpdir.join("test.txt")
>>> f.write("hello")
>>> f.read()
"hello"
nametmpdirはpytest組み込みfixtureです。同様に、monkeypatchやcapsysなどの標準fixtureも使用可能です。