pytestでのdoctest統合実践

従来のdoctest形式のテストをpytestフレームワーク内で統合実行する仕組みについて説明します。

doctest探索の設定

pytestはデフォルトでtest*.txtというパターンに一致するテキストファイルに対してdoctestを実行します。ファイル扩展子に応じてカスタマイズするには以下のように--doctest-globオプションを指定します:

pytest --doctest-glob='*.rst' --doctest-glob='*.md'

複数パターンを指定した場合、いずれかに合致するファイルがdoctest対象となります。

ファイルの文字エンコーディングを明示的に指定するには、pytest.inidoctest_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です。同様に、monkeypatchcapsysなどの標準fixtureも使用可能です。

タグ: pytest doctest docstring fixture namespace

6月11日 17:36 投稿