doctest —インタラクティブなPythonの例をテストします—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/doctest
移動先:案内検索

doctest —インタラクティブなPythonの例をテストする

ソースコード: :source: `Lib / doctest.py`



doctest モジュールは、インタラクティブなPythonセッションのように見えるテキストを検索し、それらのセッションを実行して、表示されているとおりに機能することを確認します。 doctestを使用する一般的な方法はいくつかあります。

  • すべてのインタラクティブな例が文書化されたとおりに機能することを確認することにより、モジュールのdocstringが最新であることを確認します。
  • テストファイルまたはテストオブジェクトのインタラクティブな例が期待どおりに機能することを確認して、回帰テストを実行します。
  • パッケージのチュートリアルドキュメントを作成するには、入出力の例を自由に説明します。 例と説明文のどちらが強調されているかに応じて、これには「リテラシーテスト」または「実行可能ドキュメント」のフレーバーがあります。

これは完全ですが小さなサンプルモジュールです:

"""
This is the "example" module.

The example module supplies one function, factorial().  For example,

>>> factorial(5)
120
"""

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()

example.pyをコマンドラインから直接実行すると、 doctest はその魔法のように機能します。

$ python example.py
$

出力はありません! これは正常であり、すべての例が機能したことを意味します。 -vをスクリプトに渡すと、 doctest は試行内容の詳細なログを出力し、最後に要約を出力します。

$ python example.py -v
Trying:
    factorial(5)
Expecting:
    120
ok
Trying:
    [factorial(n) for n in range(6)]
Expecting:
    [1, 1, 2, 6, 24, 120]
ok

など、最終的には次のように終わります。

Trying:
    factorial(1e100)
Expecting:
    Traceback (most recent call last):
        ...
    OverflowError: n too large
ok
2 items passed all tests:
   1 tests in __main__
   8 tests in __main__.factorial
9 tests in 2 items.
9 passed and 0 failed.
Test passed.
$

doctest を生産的に使用するために知っておく必要があるのは、これだけです。 飛び込む。 次のセクションでは、詳細を説明します。 標準のPythonテストスイートとライブラリには、doctestの例がたくさんあることに注意してください。 特に有用な例は、標準のテストファイルLib/test/test_doctest.pyにあります。

簡単な使用法:Docstringsの例を確認する

doctestの使用を開始する最も簡単な方法(ただし、必ずしもそれを継続する方法ではありません)は、各モジュールMを次のように終了することです。

if __name__ == "__main__":
    import doctest
    doctest.testmod()

次に、 doctest は、モジュールMのdocstringを調べます。

モジュールをスクリプトとして実行すると、docstringの例が実行され、検証されます。

python M.py

例が失敗しない限り、これは何も表示しません。失敗した例と失敗の原因はstdoutに出力され、出力の最終行は***Test Failed*** N failures.です。 、ここで、 N は失敗した例の数です。

代わりに-vスイッチを使用して実行してください。

python M.py -v

試行されたすべての例の詳細なレポートが、最後にさまざまな要約とともに標準出力に出力されます。

verbose=Truetestmod()に渡すことで冗長モードを強制するか、verbose=Falseを渡すことで禁止することができます。 いずれの場合も、sys.argvtestmod()によって検査されません(したがって、-vを渡すかどうかは効果がありません)。

testmod()を実行するためのコマンドラインショートカットもあります。 Pythonインタープリターに、標準ライブラリから直接doctestモジュールを実行し、コマンドラインでモジュール名を渡すように指示できます。

python -m doctest -v example.py

これにより、example.pyがスタンドアロンモジュールとしてインポートされ、 testmod()が実行されます。 ファイルがパッケージの一部であり、そのパッケージから他のサブモジュールをインポートする場合、これは正しく機能しない可能性があることに注意してください。

testmod()の詳細については、セクション Basic API を参照してください。


簡単な使用法:テキストファイルの例を確認する

doctestのもう1つの簡単なアプリケーションは、テキストファイルでインタラクティブな例をテストすることです。 これは、 testfile()関数を使用して実行できます。

import doctest
doctest.testfile("example.txt")

その短いスクリプトは、ファイルexample.txtに含まれているインタラクティブなPythonの例を実行して検証します。 ファイルの内容は、単一の巨大なdocstringであるかのように扱われます。 ファイルにPythonプログラムを含める必要はありません。 たとえば、おそらくexample.txtには次のものが含まれています。

The ``example`` module
======================

Using ``factorial``
-------------------

This is an example text file in reStructuredText format.  First import
``factorial`` from the ``example`` module:

    >>> from example import factorial

Now use it:

    >>> factorial(6)
    120

doctest.testfile("example.txt")を実行すると、このドキュメントでエラーが見つかります。

File "./example.txt", line 14, in example.txt
Failed example:
    factorial(6)
Expected:
    120
Got:
    720

testmod()と同様に、 testfile()は、例が失敗しない限り何も表示しません。 例が失敗した場合、失敗した例と失敗の原因は、 testmod()と同じ形式を使用してstdoutに出力されます。

デフォルトでは、 testfile()は呼び出し元のモジュールのディレクトリでファイルを検索します。 他の場所でファイルを検索するように指示するために使用できるオプションの引数の説明については、セクション基本API を参照してください。

testmod()と同様に、 testfile()の詳細度は、-vコマンドラインスイッチまたはオプションのキーワード引数 verbose を使用して設定できます。 ]。

testfile()を実行するためのコマンドラインショートカットもあります。 Pythonインタープリターに、標準ライブラリから直接doctestモジュールを実行し、コマンドラインでファイル名を渡すように指示できます。

python -m doctest -v example.txt

ファイル名が.pyで終わっていないため、 doctest は、 testmod()ではなく testfile()で実行する必要があると推測します。

testfile()の詳細については、セクション Basic API を参照してください。


使い方

このセクションでは、doctestがどのように機能するか、つまり、どのdocstringを調べるか、インタラクティブな例を見つける方法、使用する実行コンテキスト、例外を処理する方法、オプションフラグを使用して動作を制御する方法について詳しく説明します。 これは、doctestの例を作成するために知っておく必要のある情報です。 これらの例で実際にdoctestを実行する方法については、次のセクションを参照してください。

どのDocstringが検査されますか?

モジュールdocstring、およびすべての関数、クラス、メソッドのdocstringが検索されます。 モジュールにインポートされたオブジェクトは検索されません。

さらに、M.__test__が存在し、「true」である場合、それはdictである必要があり、各エントリは(文字列)名を関数オブジェクト、クラスオブジェクト、または文字列にマップします。 M.__test__から見つかった関数およびクラスオブジェクトのdocstringが検索され、文字列はdocstringであるかのように扱われます。 出力では、M.__test__のキーKが名前で表示されます

<name of M>.__test__.K

見つかったクラスはすべて、含まれているメソッドとネストされたクラスでdocstringをテストするために、同様に再帰的に検索されます。


Docstringの例はどのように認識されますか?

ほとんどの場合、インタラクティブコンソールセッションのコピーアンドペーストは正常に機能しますが、doctestは特定のPythonシェルの正確なエミュレーションを実行しようとはしていません。

>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
...     print("yes")
... else:
...     print("no")
...     print("NO")
...     print("NO!!!")
...
no
NO
NO!!!
>>>

期待される出力は、コードを含む最後の'>>> 'または'... '行の直後に続く必要があり、期待される出力(存在する場合)は次の'>>> 'またはすべて空白の行に拡張されます。

細字:

  • 期待される出力には、すべて空白の行を含めることはできません。このような行は、期待される出力の終了を示すために使用されるためです。 期待される出力に空白行が含まれている場合は、doctestの例に<BLANKLINE>を入れて、空白行が期待される場所に配置します。

  • すべてのハードタブ文字は、8列のタブストップを使用してスペースに展開されます。 テストされたコードによって生成された出力のタブは変更されません。 サンプル出力のハードタブはで展開されるため、コード出力にハードタブが含まれている場合、doctestが合格できる唯一の方法は、 NORMALIZE_WHITESPACE オプションまたはの場合です。ディレクティブが有効です。 または、テストを書き直して出力をキャプチャし、テストの一部として期待値と比較することもできます。 ソース内のタブのこの処理は試行錯誤によって達成され、エラーが発生しにくい方法であることが証明されています。 カスタム DocTestParser クラスを作成することにより、タブを処理するために別のアルゴリズムを使用することができます。

  • stdoutへの出力はキャプチャされますが、stderrへの出力はキャプチャされません(例外トレースバックは別の方法でキャプチャされます)。

  • インタラクティブセッションでバックスラッシュを使用して行を続ける場合、またはその他の理由でバックスラッシュを使用する場合は、生のdocstringを使用する必要があります。これにより、入力したとおりにバックスラッシュが保持されます。

    >>> def f(x):
    ...     r'''Backslashes in a raw docstring: m\n'''
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n

    それ以外の場合、円記号は文字列の一部として解釈されます。 たとえば、上記の\nは、改行文字として解釈されます。 または、doctestバージョンで各バックスラッシュを2倍にすることもできます(生の文字列は使用しないでください)。

    >>> def f(x):
    ...     '''Backslashes in a raw docstring: m\\n'''
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n
  • 開始列は重要ではありません。

    >>> assert "Easy!"
          >>> import math
              >>> math.floor(1.9)
              1

    また、例を開始した最初の'>>> '行に表示されているのと同じ数の先頭の空白文字が、期待される出力から削除されます。


実行コンテキストとは何ですか?

デフォルトでは、 doctest がテストするdocstringを見つけるたびに、Mのグローバルの浅いコピーを使用するため、テストを実行してもモジュールのグローバルは変更されません。実際のグローバルであり、Mの1つのテストで、別のテストが誤って機能する可能性のあるパンくずを残すことができないようにします。 つまり、例では、Mのトップレベルで定義された名前と、実行中のdocstringで以前に定義された名前を自由に使用できます。 例では、他のdocstringで定義されている名前を確認できません。

代わりにglobs=your_dicttestmod()または testfile()に渡すことで、実行コンテキストとして独自のdictを強制的に使用できます。


例外はどうですか?

トレースバックが例によって生成される唯一の出力である場合は、問題ありません。トレースバックを貼り付けるだけです。 1 トレースバックには、急速に変化する可能性のある詳細(正確なファイルパスや行番号など)が含まれているため、これはdoctestが受け入れる内容に柔軟性を持たせるために懸命に機能する1つのケースです。

簡単な例:

>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

ValueError が発生すると、そのdoctestは成功し、list.remove(x): x not in listの詳細が示されます。

例外の予想される出力は、トレースバックヘッダーで開始する必要があります。これは、例の最初の行と同じようにインデントされた、次の2行のいずれかです。

Traceback (most recent call last):
Traceback (innermost last):

トレースバックヘッダーの後にはオプションのトレースバックスタックが続き、その内容はdoctestによって無視されます。 トレースバックスタックは通常省略されるか、インタラクティブセッションから逐語的にコピーされます。

トレースバックスタックの後には、最も興味深い部分、つまり例外タイプと詳細を含む行が続きます。 これは通常、トレースバックの最後の行ですが、例外に複数行の詳細がある場合は、複数の行にまたがることがあります。

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: multi
    line
detail

最後の3行( ValueError で始まる)は、例外のタイプおよび詳細と比較され、残りは無視されます。

例に重要なドキュメントの価値を追加しない限り、ベストプラクティスはトレースバックスタックを省略することです。 したがって、最後の例はおそらく次のように優れています。

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
    ...
ValueError: multi
    line
detail

トレースバックは非常に特別に扱われることに注意してください。 特に、書き直された例では、...の使用は、doctestの ELLIPSIS オプションとは無関係です。 この例の省略記号は、省略したり、3つ(または300)のコンマや数字、またはモンティパイソンのスキットのインデントされたトランスクリプトにすることもできます。

一度読む必要があるが、覚えておく必要のない詳細:

  • Doctestは、期待される出力が例外トレースバックからのものか、通常の印刷からのものかを推測できません。 したがって、たとえば、ValueError: 42 is primeを期待する例は、 ValueError が実際に発生するかどうか、または例が単にそのトレースバックテキストを出力するかどうかを渡します。 実際には、通常の出力がトレースバックヘッダー行で始まることはめったにないため、これによって実際の問題が発生することはありません。
  • トレースバックスタックの各行(存在する場合)は、例の最初の行よりもさらにインデントする必要があります。またはは英数字以外の文字で始まります。 同じようにインデントされ、英数字で始まるトレースバックヘッダーに続く最初の行は、例外の詳細の開始と見なされます。 もちろん、これは本物のトレースバックに対して正しいことをします。
  • IGNORE_EXCEPTION_DETAIL doctestオプションが指定されている場合、左端のコロンに続くすべてと例外名のモジュール情報はすべて無視されます。
  • 対話型シェルは、一部の SyntaxError のトレースバックヘッダー行を省略しています。 ただし、doctestは、トレースバックヘッダー行を使用して、例外と非例外を区別します。 したがって、トレースバックヘッダーを省略した SyntaxError をテストする必要があるまれなケースでは、テスト例にトレースバックヘッダー行を手動で追加する必要があります。
  • 一部の SyntaxError の場合、Pythonは^マーカーを使用して、構文エラーの文字位置を表示します。

    >>> 1 1
      File "<stdin>", line 1
        1 1
          ^
    SyntaxError: invalid syntax

    エラーの位置を示す行は、例外のタイプと詳細の前にあるため、doctestではチェックされません。 たとえば、^マーカーが間違った場所に配置されていても、次のテストは合格です。

    >>> 1 1
      File "<stdin>", line 1
        1 1
        ^
    SyntaxError: invalid syntax


オプションフラグ

いくつかのオプションフラグは、doctestの動作のさまざまな側面を制御します。 フラグのシンボリック名はモジュール定数として提供され、ビットごとにOR演算して、さまざまな関数に渡すことができます。 この名前は、 doctestディレクティブでも使用でき、-oオプションを介してdoctestコマンドラインインターフェイスに渡すことができます。

バージョン3.4の新機能: -oコマンドラインオプション。


オプションの最初のグループは、テストセマンティクスを定義し、実際の出力が例の期待される出力と一致するかどうかをdoctestが決定する方法の側面を制御します。

doctest.DONT_ACCEPT_TRUE_FOR_1
デフォルトでは、期待される出力ブロックに1のみが含まれている場合、1またはTrueのみを含む実際の出力ブロックは一致と見なされ、0FalseDONT_ACCEPT_TRUE_FOR_1 が指定されている場合、どちらの置換も許可されません。 デフォルトの動作は、Pythonが多くの関数の戻り型を整数からブール値に変更したことに対応しています。 「小さな整数」の出力を期待するdoctestは、これらの場合でも機能します。 このオプションはおそらくなくなるでしょうが、数年はありません。

doctest.DONT_ACCEPT_BLANKLINE
デフォルトでは、期待される出力ブロックに文字列<BLANKLINE>のみを含む行が含まれている場合、その行は実際の出力の空白行と一致します。 真に空白行は期待される出力を区切るため、これが空白行が期待されることを伝える唯一の方法です。 DONT_ACCEPT_BLANKLINE が指定されている場合、この置換は許可されません。
doctest.NORMALIZE_WHITESPACE
指定すると、空白のすべてのシーケンス(空白と改行)は等しいものとして扱われます。 期待される出力内の空白のシーケンスは、実際の出力内の空白のシーケンスと一致します。 デフォルトでは、空白は完全に一致する必要があります。 NORMALIZE_WHITESPACE は、予想される出力の行が非常に長く、ソース内の複数の行に折り返したい場合に特に便利です。

doctest.ELLIPSIS
指定すると、期待される出力の省略記号マーカー(...)は、実際の出力の任意の部分文字列と一致する可能性があります。 これには、行の境界にまたがる部分文字列と空の部分文字列が含まれるため、これを単純に使用することをお勧めします。 複雑な使用は、同じ種類の「おっと、マッチしすぎた!」につながる可能性があります。 .*が正規表現になりやすいことに驚いています。
doctest.IGNORE_EXCEPTION_DETAIL

指定すると、例外の詳細が一致しなくても、予期されるタイプの例外が発生すると、例外を予期する例が渡されます。 たとえば、ValueError: 42を期待する例は、発生した実際の例外がValueError: 3*14の場合は成功しますが、 TypeError が発生した場合などは失敗します。

また、Python 3doctestレポートで使用されているモジュール名も無視されます。 したがって、これらのバリエーションは両方とも、テストがPython2.7またはPython3.2(またはそれ以降のバージョン)のどちらで実行されているかに関係なく、指定されたフラグで機能します。

>>> raise CustomError('message')
Traceback (most recent call last):
CustomError: message

>>> raise CustomError('message')
Traceback (most recent call last):
my_module.CustomError: message

ELLIPSIS を使用して例外メッセージの詳細を無視することもできますが、モジュールの詳細が例外名の一部として出力されるかどうかに基づいて、このようなテストが失敗する場合があります。 IGNORE_EXCEPTION_DETAIL とPython2.3の詳細を使用することも、例外の詳細を気にせず、Python 2.3以前で引き続き合格するdoctestを作成する唯一の明確な方法です(これらのリリースは[X243Xをサポートしていません)。 ] doctestディレクティブ、無関係なコメントとして無視します)。 例えば:

>>> (1, 2)[3] = 'moo'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object doesn't support item assignment

Python 2.4で詳細が「しない」ではなく「しない」に変更された場合でも、Python2.3以降のPythonバージョンではフラグが指定されて渡されます。

バージョン3.2で変更: IGNORE_EXCEPTION_DETAIL は、テスト中の例外を含むモジュールに関連する情報もすべて無視するようになりました。

doctest.SKIP

指定されている場合は、例をまったく実行しないでください。 これは、doctestの例がドキュメントとテストケースの両方として機能し、ドキュメントの目的で例を含める必要があるが、チェックしないでください。 たとえば、例の出力はランダムである可能性があります。 または、例は、テストドライバーが利用できないリソースに依存する場合があります。

SKIPフラグは、例を一時的に「コメントアウト」するためにも使用できます。

doctest.COMPARISON_FLAGS
上記のすべての比較フラグを一緒にビットマスクまたは 'します。

オプションの2番目のグループは、テストの失敗を報告する方法を制御します。

doctest.REPORT_UDIFF
指定すると、複数行の予想出力と実際の出力に関連する障害が、統一された差分を使用して表示されます。
doctest.REPORT_CDIFF
指定すると、複数行の予想出力と実際の出力に関連する障害がコンテキスト差分を使用して表示されます。
doctest.REPORT_NDIFF
指定すると、一般的なndiff.pyユーティリティと同じアルゴリズムを使用して、difflib.Differによって差異が計算されます。 これは、行内および行間の違いをマークする唯一の方法です。 たとえば、期待される出力の行に数字1が含まれ、実際の出力に文字lが含まれる場合、不一致の列位置を示すキャレットが付いた行が挿入されます。
doctest.REPORT_ONLY_FIRST_FAILURE
指定すると、各doctestで最初に失敗した例を表示しますが、残りのすべての例の出力は抑制します。 これにより、doctestが以前の失敗のために壊れた正しい例を報告するのを防ぎます。 ただし、最初の失敗とは関係なく失敗する誤った例を非表示にする場合もあります。 REPORT_ONLY_FIRST_FAILURE が指定されている場合でも、残りの例は実行され、報告された障害の総数にカウントされます。 出力のみが抑制されます。
doctest.FAIL_FAST

指定した場合、最初に失敗した例の後で終了し、残りの例を実行しようとしないでください。 したがって、報告される障害の数は最大で1になります。 最初の失敗後の例ではデバッグ出力すら生成されないため、このフラグはデバッグ中に役立つ場合があります。

doctestコマンドラインは、-o FAIL_FASTの省略形としてオプション-fを受け入れます。

バージョン3.4の新機能。

doctest.REPORTING_FLAGS
上記のすべてのレポートフラグをまとめるビットマスク。

新しいオプションフラグ名を登録する方法もありますが、サブクラス化を介して doctest 内部を拡張する場合を除いて、これは役に立ちません。

doctest.register_optionflag(name)

指定された名前で新しいオプションフラグを作成し、新しいフラグの整数値を返します。 register_optionflag()は、 OutputChecker または DocTestRunner をサブクラス化するときに使用して、サブクラスでサポートされる新しいオプションを作成できます。 register_optionflag()は、常に次のイディオムを使用して呼び出す必要があります。

MY_FLAG = register_optionflag('MY_FLAG')


指令

Doctestディレクティブを使用して、個々の例のオプションフラグを変更できます。 Doctestディレクティブは、例のソースコードに続く特別なPythonコメントです。

 ディレクティブ             ::=  "#" "doctest:" directive_options
  directive_options     ::=  directive_option ("," directive_option)\*
  directive_option      ::=  on_or_off directive_option_name
  on_or_off             ::=  "+" \| "-"
  directive_option_name ::=  "DONT_ACCEPT_BLANKLINE" \| "NORMALIZE_WHITESPACE" \| ...

+または-とディレクティブオプション名の間に空白は使用できません。 ディレクティブオプション名は、上記で説明したオプションフラグ名のいずれかです。

例のdoctestディレクティブは、その1つの例のdoctestの動作を変更します。 +を使用して名前付き動作を有効にするか、-を使用して無効にします。

たとえば、このテストは合格です。

>>> print(list(range(20))) 
[0,   1,  2,  3,  4,  5,  6,  7,  8,  9,
10,  11, 12, 13, 14, 15, 16, 17, 18, 19]

ディレクティブがないと、実際の出力の前に1桁のリスト要素の前に2つのブランクがないため、および実際の出力が1行にあるため、失敗します。 このテストも合格し、そのためのディレクティブも必要です。

>>> print(list(range(20))) 
[0, 1, ..., 18, 19]

複数のディレクティブは、コンマで区切って1つの物理行で使用できます。

>>> print(list(range(20))) 
[0,    1, ...,   18,    19]

1つの例で複数のディレクティブコメントが使用されている場合、それらは組み合わされます。

>>> print(list(range(20))) 
...                        
[0,    1, ...,   18,    19]

前の例が示すように、ディレクティブのみを含む例に...行を追加できます。 これは、例が長すぎてディレクティブが同じ行に快適に収まらない場合に役立ちます。

>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... 
[0, ..., 4, 10, ..., 19, 30, ..., 39]

すべてのオプションはデフォルトで無効になっており、ディレクティブはそれらが表示される例にのみ適用されるため、通常、オプションを有効にする(ディレクティブの+を介して)ことが唯一の意味のある選択肢であることに注意してください。 ただし、オプションフラグは、doctestを実行する関数に渡して、異なるデフォルトを確立することもできます。 このような場合、ディレクティブで-を介してオプションを無効にすると便利です。


警告

doctest は、期待される出力に完全に一致することを要求することに真剣に取り組んでいます。 1文字でも一致しない場合、テストは失敗します。 Pythonが何をするのか、そして出力について保証しないのかを正確に学ぶので、これはおそらく数回あなたを驚かせるでしょう。 たとえば、セットを印刷する場合、Pythonは要素が特定の順序で印刷されることを保証しないため、次のようなテストを行います。

>>> foo()
{"Hermione", "Harry"}

脆弱です! 回避策の1つは、

>>> foo() == {"Hermione", "Harry"}
True

代わりは。 もう一つはすることです

>>> d = sorted(foo())
>>> d
['Harry', 'Hermione']

ノート

Python 3.6より前は、dictを出力するときに、Pythonはキーと値のペアが特定の順序で出力されることを保証していませんでした。


他にもありますが、あなたはその考えを理解します。

もう1つの悪い考えは、次のようなオブジェクトアドレスを埋め込んだものを印刷することです。

>>> id(1.0) # certain to fail some of the time
7948648
>>> class C: pass
>>> C()   # the default repr() for instances embeds an address
<__main__.C instance at 0x00AC18F0>

ELLIPSIS ディレクティブは、最後の例に適したアプローチを提供します。

>>> C() 
<__main__.C instance at 0x...>

Pythonは浮動小数点形式のプラットフォームCライブラリに依存し、Cライブラリの品質はここでは大きく異なるため、浮動小数点数もプラットフォーム間で出力がわずかに変動する可能性があります。

>>> 1./7  # risky
0.14285714285714285
>>> print(1./7) # safer
0.142857142857
>>> print(round(1./7, 6)) # much safer
0.142857

I/2.**Jの形式の番号は、すべてのプラットフォームで安全です。私は、doctestの例を考案して、その形式の番号を作成することがよくあります。

>>> 3./4  # utterly safe
0.75

単純な分数も人々が理解しやすく、それはより良いドキュメントになります。


基本的なAPI

関数 testmod()および testfile()は、ほとんどの基本的な使用に十分なdoctestへの単純なインターフェースを提供します。 これら2つの関数の正式な紹介については、セクション簡単な使用法:Docstringsの例の確認および簡単な使用法:テキストファイルの例の確認を参照してください。

doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)

filename を除くすべての引数はオプションであり、キーワード形式で指定する必要があります。

filename という名前のファイルのテスト例。 (failure_count, test_count)を返します。

オプションの引数 module_relative は、ファイル名の解釈方法を指定します。

  • module_relativeTrue(デフォルト)の場合、 filename はOSに依存しないモジュール相対パスを指定します。 デフォルトでは、このパスは呼び出し元のモジュールのディレクトリからの相対パスです。 ただし、 package 引数が指定されている場合、それはそのパッケージに関連しています。 OSに依存しないようにするには、ファイル名/文字を使用してパスセグメントを区切る必要があります。絶対パスではない場合があります(つまり、/で始まらない場合があります)。

  • module_relativeFalseの場合、 filename はOS固有のパスを指定します。 パスは絶対パスでも相対パスでもかまいません。 相対パスは、現在の作業ディレクトリを基準にして解決されます。

オプションの引数 name は、テストの名前を示します。 デフォルト、またはNoneの場合、os.path.basename(filename)が使用されます。

オプションの引数 package は、Pythonパッケージ、またはモジュール相対ファイル名のベースディレクトリとしてディレクトリを使用する必要があるPythonパッケージの名前です。 パッケージが指定されていない場合、呼び出し元のモジュールのディレクトリがモジュール相対ファイル名のベースディレクトリとして使用されます。 module_relativeFalseの場合、パッケージを指定するとエラーになります。

オプションの引数 globs は、例を実行するときにグローバルとして使用されるdictを提供します。 このdictの新しい浅いコピーがdoctest用に作成されるため、その例は白紙の状態から始まります。 デフォルト、またはNoneの場合、新しい空のdictが使用されます。

オプションの引数 extraglobs は、例の実行に使用されるグローバルにマージされたdictを提供します。 これは dict.update()のように機能します。 globsextraglobs に共通のキーがある場合、 extraglobs の関連する値が連想配列。 デフォルト、またはNoneの場合、追加のグローバルは使用されません。 これは、doctestのパラメータ化を可能にする高度な機能です。 たとえば、doctestは、クラスの総称名を使用して基本クラスに対して記述し、 extraglobs dictを渡して、テストするサブクラスに総称名をマッピングすることにより、任意の数のサブクラスをテストするために再利用できます。 。

オプションの引数 verbose は、trueの場合は多くのものを出力し、falseの場合は失敗のみを出力します。 デフォルト、またはNoneの場合、'-v'sys.argvにある場合にのみtrueになります。

オプションの引数 report は、trueの場合は最後に要約を出力し、それ以外の場合は最後に何も出力しません。 詳細モードでは、要約は詳細です。それ以外の場合、要約は非常に簡潔です(実際、すべてのテストに合格した場合は空です)。

オプションの引数 optionflags (デフォルト値0)は、オプションフラグのビット単位のOR を取ります。 セクションオプションフラグを参照してください。

オプションの引数 raise_on_error のデフォルトはfalseです。 trueの場合、例では最初の失敗または予期しない例外が発生したときに例外が発生します。 これにより、障害を事後的にデバッグできます。 デフォルトの動作は、サンプルの実行を継続することです。

オプションの引数 parser は、ファイルからテストを抽出するために使用する必要がある DocTestParser (またはサブクラス)を指定します。 デフォルトでは通常のパーサー(つまり、DocTestParser())になります。

オプションの引数 encoding は、ファイルをUnicodeに変換するために使用する必要があるエンコーディングを指定します。

doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)

すべての引数はオプションであり、 m を除くすべてをキーワード形式で指定する必要があります。

モジュール m (または m が提供されていないかNoneの場合はモジュール __ main __ )から到達可能な関数およびクラスのdocstringのテスト例m.__doc__で。

また、dict m.__test__から到達可能なテスト例もあります。 m.__test__は、名前(文字列)を関数、クラス、および文字列にマップします。 関数とクラスのdocstringで例を検索します。 文字列は、docstringであるかのように直接検索されます。

モジュール m に属するオブジェクトにアタッチされたdocstringのみが検索されます。

(failure_count, test_count)を返します。

オプションの引数 name は、モジュールの名前を示します。 デフォルト、またはNoneの場合、m.__name__が使用されます。

オプションの引数 exclude_empty のデフォルトはfalseです。 trueの場合、doctestが見つからないオブジェクトは考慮から除外されます。 デフォルトは下位互換性ハックであるため、doctest.master.summarize()testmod()と組み合わせて使用しているコードは、テストなしでオブジェクトの出力を取得し続けます。 新しい DocTestFinder コンストラクターの exclude_empty 引数のデフォルトはtrueです。

オプションの引数 extraglobsverbosereportoptionflagsraise_on_error 、および globs globs のデフォルトがm.__dict__であることを除いて、上記の関数 testfile()と同じです。

doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)

オブジェクト f に関連するテスト例。 たとえば、 f は、文字列、モジュール、関数、またはクラスオブジェクトの場合があります。

辞書引数 globs の浅いコピーが、実行コンテキストに使用されます。

オプションの引数 name は失敗メッセージで使用され、デフォルトは"NoName"です。

オプションの引数 verbose がtrueの場合、障害がなくても出力が生成されます。 デフォルトでは、出力は失敗例の場合にのみ生成されます。

オプションの引数 compileflags は、例を実行するときにPythonコンパイラーが使用する必要のあるフラグのセットを提供します。 デフォルト、またはNoneの場合、フラグは globs にある将来の機能のセットに対応して推定されます。

オプションの引数 optionflags は、上記の関数 testfile()と同様に機能します。


ユニットテストAPI

doctestされたモジュールのコレクションが増えるにつれて、すべてのdoctestを体系的に実行する方法が必要になります。 doctest は、モジュールとdoctestを含むテキストファイルから unittest テストスイートを作成するために使用できる2つの関数を提供します。 unittest テスト検出と統合するには、テストモジュールにload_tests()関数を含めます。

import unittest
import doctest
import my_module_with_doctests

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
    return tests

doctestを使用してテキストファイルとモジュールから unittest.TestSuite インスタンスを作成するための2つの主要な関数があります。

doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)

doctestテストを1つ以上のテキストファイルから unittest.TestSuite に変換します。

返された unittest.TestSuite は、unittestフレームワークによって実行され、各ファイルでインタラクティブな例を実行します。 いずれかのファイルの例が失敗すると、合成された単体テストが失敗し、failureException例外が発生して、テストを含むファイルの名前と(場合によってはおおよその)行番号が示されます。

検査するテキストファイルへの1つ以上のパス(文字列として)を渡します。

オプションは、キーワード引数として提供できます。

オプションの引数 module_relative は、パスのファイル名をどのように解釈するかを指定します。

  • module_relativeTrue(デフォルト)の場合、 paths の各ファイル名はOSに依存しないモジュール相対パスを指定します。 デフォルトでは、このパスは呼び出し元のモジュールのディレクトリからの相対パスです。 ただし、 package 引数が指定されている場合、それはそのパッケージに関連しています。 OSに依存しないようにするには、各ファイル名で/文字を使用してパスセグメントを区切る必要があります。絶対パスではない場合があります(つまり、/で始まらない場合があります)。

  • module_relativeFalseの場合、 path の各ファイル名はOS固有のパスを指定します。 パスは絶対パスでも相対パスでもかまいません。 相対パスは、現在の作業ディレクトリを基準にして解決されます。

オプションの引数 package は、PythonパッケージまたはPythonパッケージの名前であり、そのディレクトリは、パスのモジュール相対ファイル名のベースディレクトリとして使用する必要があります。 パッケージが指定されていない場合、呼び出し元のモジュールのディレクトリがモジュール相対ファイル名のベースディレクトリとして使用されます。 module_relativeFalseの場合、パッケージを指定するとエラーになります。

オプションの引数 setUp は、テストスイートのセットアップ関数を指定します。 これは、各ファイルでテストを実行する前に呼び出されます。 setUp 関数には DocTest オブジェクトが渡されます。 setUp関数は、テストに合格した globs 属性として、テストグローバルにアクセスできます。

オプションの引数 tearDown は、テストスイートの分解関数を指定します。 これは、各ファイルでテストを実行した後に呼び出されます。 tearDown 関数には DocTest オブジェクトが渡されます。 setUp関数は、テストに合格した globs 属性として、テストグローバルにアクセスできます。

オプションの引数 globs は、テストの初期グローバル変数を含む辞書です。 この辞書の新しいコピーは、テストごとに作成されます。 デフォルトでは、 globs は新しい空の辞書です。

オプションの引数 optionflags は、個々のオプションフラグをor-ingして作成された、テストのデフォルトのdoctestオプションを指定します。 セクションオプションフラグを参照してください。 レポートオプションを設定するためのより良い方法については、以下の関数 set_unittest_reportflags()を参照してください。

オプションの引数 parser は、ファイルからテストを抽出するために使用する必要がある DocTestParser (またはサブクラス)を指定します。 デフォルトでは通常のパーサー(つまり、DocTestParser())になります。

オプションの引数 encoding は、ファイルをUnicodeに変換するために使用する必要があるエンコーディングを指定します。

グローバル__file__は、 DocFileSuite()を使用してテキストファイルからロードされたdoctestに提供されるグローバルに追加されます。

doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, checker=None)

モジュールのdoctestテストを unittest.TestSuite に変換します。

返された unittest.TestSuite は、unittestフレームワークによって実行され、モジュール内の各doctestを実行します。 doctestのいずれかが失敗すると、合成された単体テストが失敗し、failureException例外が発生して、テストを含むファイルの名前と(場合によってはおおよその)行番号が示されます。

オプションの引数 module は、テストするモジュールを提供します。 モジュールオブジェクトまたは(場合によっては点線の)モジュール名にすることができます。 指定しない場合、この関数を呼び出すモジュールが使用されます。

オプションの引数 globs は、テストの初期グローバル変数を含む辞書です。 この辞書の新しいコピーは、テストごとに作成されます。 デフォルトでは、 globs は新しい空の辞書です。

オプションの引数 extraglobs は、 globs にマージされるグローバル変数の追加セットを指定します。 デフォルトでは、追加のグローバルは使用されません。

オプションの引数 test_finder は、モジュールからdoctestを抽出するために使用される DocTestFinder オブジェクト(またはドロップイン置換)です。

オプションの引数 setUptearDown 、および optionflags は、上記の関数 DocFileSuite()の場合と同じです。

この関数は、 testmod()と同じ検索手法を使用します。

裏で、 DocTestSuite()doctest.DocTestCaseインスタンスから unittest.TestSuite を作成し、DocTestCaseunittestのサブクラスです。 TestCaseDocTestCaseはここでは文書化されていません(これは内部の詳細です)が、そのコードを研究することで、 unittest 統合の正確な詳細に関する質問に答えることができます。

同様に、 DocFileSuite()doctest.DocFileCaseインスタンスから unittest.TestSuite を作成し、DocFileCaseDocTestCaseのサブクラスです。

したがって、 unittest.TestSuite を作成する両方の方法で、DocTestCaseのインスタンスを実行します。 これは微妙な理由で重要です。 doctest 関数を自分で実行する場合、オプションフラグを doctest 関数に渡すことにより、使用中の doctest オプションを直接制御できます。 。 ただし、 unittest フレームワークを作成している場合、 unittest は、テストをいつどのように実行するかを最終的に制御します。 フレームワークの作成者は通常、 doctest レポートオプション(たとえば、コマンドラインオプションで指定)を制御したいと考えていますが、オプションを unittest から doctest に渡す方法はありません。 ]テストランナー。

このため、 doctest は、次の関数を介して、 unittest サポートに固有の doctest レポートフラグの概念もサポートします。

doctest.set_unittest_reportflags(flags)

使用する doctest レポートフラグを設定します。

引数 flags は、オプションフラグのビット単位のOR を取ります。 セクションオプションフラグを参照してください。 「レポートフラグ」のみを使用できます。

これはモジュールグローバル設定であり、モジュール unittest によって実行される将来のすべてのドキュメントテストに影響します。DocTestCaserunTest()メソッドは、次の場合にテストケースに指定されたオプションフラグを調べます。 DocTestCaseインスタンスが構築されました。 レポートフラグが指定されていない場合(これは一般的で予想されるケースです)、 doctestunittest レポートフラグはオプションフラグにビットごとにORされ、そのように拡張されたオプションフラグは、doctestを実行するために作成された DocTestRunner インスタンスに渡されます。 DocTestCaseインスタンスの構築時にレポートフラグが指定された場合、 doctestunittest レポートフラグは無視されます。

関数が呼び出される前に有効だった unittest レポートフラグの値は、関数によって返されます。


高度なAPI

基本的なAPIは、doctestを使いやすくすることを目的としたシンプルなラッパーです。 かなり柔軟性があり、ほとんどのユーザーのニーズを満たす必要があります。 ただし、テストをよりきめ細かく制御する必要がある場合、またはdoctestの機能を拡張したい場合は、高度なAPIを使用する必要があります。

高度なAPIは、doctestケースから抽出されたインタラクティブな例を格納するために使用される2つのコンテナクラスを中心に展開します。

  • :期待される出力とペアになっている単一のPython ステートメント
  • DocTestExample のコレクションで、通常は単一のdocstringまたはテキストファイルから抽出されます。

doctestの例を検索、解析、実行、およびチェックするために、追加の処理クラスが定義されています。

  • DocTestFinder :指定されたモジュール内のすべてのdocstringを検索し、 DocTestParser を使用して、インタラクティブな例を含むすべてのdocstringから DocTest を作成します。
  • DocTestParser :文字列(オブジェクトのdocstringなど)から DocTest オブジェクトを作成します。
  • DocTestRunnerDocTest の例を実行し、 OutputChecker を使用して出力を検証します。
  • OutputChecker :doctestの例からの実際の出力を期待される出力と比較し、それらが一致するかどうかを判断します。

これらの処理クラス間の関係は、次の図に要約されています。

                            list of:
+------+                   +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+    |        ^     +---------+     |       ^    (printed)
            |        |     | Example |     |       |
            v        |     |   ...   |     v       |
           DocTestParser   | Example |   OutputChecker
                           +---------+

DocTestオブジェクト

class doctest.DocTest(examples, globs, name, filename, lineno, docstring)

単一の名前空間で実行する必要があるdoctestの例のコレクション。 コンストラクター引数は、同じ名前の属性を初期化するために使用されます。

DocTest は、次の属性を定義します。 これらはコンストラクターによって初期化されるため、直接変更しないでください。

examples

このテストで実行する必要がある個々のインタラクティブなPythonの例をエンコードする Example オブジェクトのリスト。

globs

例を実行する名前空間(別名グローバル)。 これは、名前を値にマッピングする辞書です。 例によって行われた名前空間への変更(新しい変数のバインドなど)は、テストの実行後に globs に反映されます。

name

DocTest を識別する文字列名。 通常、これはテストが抽出されたオブジェクトまたはファイルの名前です。

filename

この DocTest が抽出されたファイルの名前。 または、ファイル名が不明な場合、または DocTest がファイルから抽出されなかった場合はNone

lineno

この DocTest が始まるファイル名内の行番号、または行番号が使用できない場合はNone。 この行番号は、ファイルの先頭を基準にしてゼロに基づいています。

docstring

テストが抽出された文字列、または文字列が使用できない場合、またはテストが文字列から抽出されなかった場合はNone


オブジェクトの例

class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)

Pythonステートメントとその期待される出力で構成される単一のインタラクティブな例。 コンストラクター引数は、同じ名前の属性を初期化するために使用されます。

Example は、次の属性を定義します。 これらはコンストラクターによって初期化されるため、直接変更しないでください。

source

例のソースコードを含む文字列。 このソースコードは単一のPythonステートメントで構成され、常に改行で終わります。 コンストラクターは、必要に応じて改行を追加します。

want

例のソースコードの実行から期待される出力(stdoutから、または例外の場合はトレースバックから)。 want は、出力が予期されていない場合を除き、改行で終了します。出力が予期されていない場合は、空の文字列です。 コンストラクターは、必要に応じて改行を追加します。

exc_msg

例が例外を生成すると予想される場合、例によって生成される例外メッセージ。 または、例外を生成することが予想されない場合はNone。 この例外メッセージは、 traceback.format_exception_only()の戻り値と比較されます。 exc_msg は、Noneでない限り、改行で終わります。 コンストラクターは、必要に応じて改行を追加します。

lineno

この例を含む文字列内の、例が始まる行番号。 この行番号は、含まれている文字列の先頭に関してゼロベースです。

indent

含まれている文字列内の例のインデント、つまり、例の最初のプロンプトの前にあるスペース文字の数。

options

オプションフラグからTrueまたはFalseへの辞書マッピング。これは、この例のデフォルトオプションをオーバーライドするために使用されます。 このディクショナリに含まれていないオプションフラグは、デフォルト値( DocTestRunneroptionflagsで指定)のままになります。 デフォルトでは、オプションは設定されていません。


DocTestFinderオブジェクト

class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)

特定のオブジェクトに関連する DocTest を、そのdocstringおよび含まれているオブジェクトのdocstringから抽出するために使用される処理クラス。 DocTest は、モジュール、クラス、関数、メソッド、staticmethods、classmethods、およびプロパティから抽出できます。

オプションの引数 verbose を使用して、ファインダーによって検索されたオブジェクトを表示できます。 デフォルトはFalse(出力なし)です。

オプションの引数 parser は、docstringからdoctestを抽出するために使用される DocTestParser オブジェクト(またはドロップイン置換)を指定します。

オプションの引数 recurse がfalseの場合、 DocTestFinder.find()は指定されたオブジェクトのみを調べ、含まれているオブジェクトは調べません。

オプションの引数 exclude_empty がfalseの場合、 DocTestFinder.find()には、空のdocstringを持つオブジェクトのテストが含まれます。

DocTestFinder は、次のメソッドを定義します。

find(obj[, name][, module][, globs][, extraglobs])

obj のdocstringまたはそれに含まれるオブジェクトのdocstringのいずれかによって定義された DocTest のリストを返します。

オプションの引数 name は、オブジェクトの名前を指定します。 この名前は、返される DocTest の名前を作成するために使用されます。 name が指定されていない場合は、obj.__name__が使用されます。

オプションのパラメータ module は、指定されたオブジェクトを含むモジュールです。 モジュールが指定されていないか、Noneの場合、テストファインダーは正しいモジュールを自動的に判別しようとします。 オブジェクトのモジュールが使用されます:

  • デフォルトの名前空間として、 globs が指定されていない場合。

  • DocTestFinderが他のモジュールからインポートされたオブジェクトからDocTestを抽出しないようにするため。 ( module 以外のモジュールを含む含まれているオブジェクトは無視されます。)

  • オブジェクトを含むファイルの名前を検索します。

  • ファイル内のオブジェクトの行番号を見つけるのに役立ちます。

moduleFalseの場合、モジュールの検索は行われません。 これはあいまいで、主にdoctest自体のテストで使用されます。 moduleFalseであるか、Noneであるが自動的に検出されない場合、すべてのオブジェクトはに属していると見なされます。 (存在しない)モジュールであるため、含まれているすべてのオブジェクトが(再帰的に)doctestを検索されます。

DocTest のグローバルは、 globsextraglobs を組み合わせて形成されます( extraglobs のバインディングは、 globs のバインディングをオーバーライドします) )。 グローバルディクショナリの新しい浅いコピーが DocTest ごとに作成されます。 globs が指定されていない場合、指定されている場合はデフォルトでモジュールの __ dict __ になり、指定されていない場合は{}になります。 extraglobs が指定されていない場合、デフォルトで{}になります。


DocTestParserオブジェクト

class doctest.DocTestParser

文字列からインタラクティブな例を抽出し、それらを使用して DocTest オブジェクトを作成するために使用される処理クラス。

DocTestParser は、次のメソッドを定義します。

get_doctest(string, globs, name, filename, lineno)

指定された文字列からすべてのdoctestの例を抽出し、それらを DocTest オブジェクトに収集します。

globsnamefilename 、および lineno は、新しい DocTest オブジェクトの属性です。 詳細については、 DocTest のドキュメントを参照してください。

get_examples(string, name='<string>')

指定された文字列からすべてのdoctestの例を抽出し、それらを Example オブジェクトのリストとして返します。 行番号は0から始まります。 オプションの引数 name は、この文字列を識別する名前であり、エラーメッセージにのみ使用されます。

parse(string, name='<string>')

与えられた文字列を例と間にあるテキストに分割し、それらを交互の Example と文字列のリストとして返します。 Example の行番号は0から始まります。 オプションの引数 name は、この文字列を識別する名前であり、エラーメッセージにのみ使用されます。


DocTestRunnerオブジェクト

class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)

DocTest のインタラクティブな例を実行および検証するために使用される処理クラス。

期待される出力と実際の出力の比較は、 OutputChecker によって行われます。 この比較は、いくつかのオプションフラグを使用してカスタマイズできます。 詳細については、セクションオプションフラグを参照してください。 オプションフラグが不十分な場合は、 OutputChecker のサブクラスをコンストラクターに渡すことで比較をカスタマイズすることもできます。

テストランナーの表示出力は、2つの方法で制御できます。 まず、出力関数をTestRunner.run()に渡すことができます。 この関数は、表示する必要のある文字列を使用して呼び出されます。 デフォルトはsys.stdout.writeです。 出力のキャプチャが不十分な場合は、DocTestRunnerをサブクラス化し、メソッド report_start()report_success()report_unexpected_exception()をオーバーライドすることで表示出力をカスタマイズすることもできます。 、および report_failure()

オプションのキーワード引数 checker は、期待される出力をdoctestの例の実際の出力と比較するために使用する必要がある OutputChecker オブジェクト(またはドロップイン置換)を指定します。

オプションのキーワード引数 verbose は、 DocTestRunner の詳細度を制御します。 verboseTrueの場合、実行時に各例に関する情報が出力されます。 verboseFalseの場合、失敗のみが出力されます。 verbose が指定されていない場合、またはNoneの場合、コマンドラインスイッチ-vが使用されていれば、冗長出力が使用されます。

オプションのキーワード引数 optionflags を使用して、テストランナーが期待される出力を実際の出力と比較する方法、および失敗を表示する方法を制御できます。 詳細については、セクションオプションフラグを参照してください。

DocTestParser は、次のメソッドを定義します。

report_start(out, test, example)

テストランナーが指定された例を処理しようとしていることを報告します。 このメソッドは、 DocTestRunner のサブクラスが出力をカスタマイズできるようにするために提供されています。 直接呼び出すべきではありません。

example は、これから処理される例です。 test は、例を含むテストです。 out は、 DocTestRunner.run()に渡された出力関数です。

report_success(out, test, example, got)

与えられた例が正常に実行されたことを報告します。 このメソッドは、 DocTestRunner のサブクラスが出力をカスタマイズできるようにするために提供されています。 直接呼び出すべきではありません。

example は、これから処理される例です。 got は、例からの実際の出力です。 test は、 example を含むテストです。 out は、 DocTestRunner.run()に渡された出力関数です。

report_failure(out, test, example, got)

与えられた例が失敗したことを報告してください。 このメソッドは、 DocTestRunner のサブクラスが出力をカスタマイズできるようにするために提供されています。 直接呼び出すべきではありません。

example は、これから処理される例です。 got は、例からの実際の出力です。 test は、 example を含むテストです。 out は、 DocTestRunner.run()に渡された出力関数です。

report_unexpected_exception(out, test, example, exc_info)

与えられた例が予期しない例外を引き起こしたことを報告してください。 このメソッドは、 DocTestRunner のサブクラスが出力をカスタマイズできるようにするために提供されています。 直接呼び出すべきではありません。

example は、これから処理される例です。 exc_info は、予期しない例外に関する情報を含むタプルです( sys.exc_info()によって返されます)。 test は、 example を含むテストです。 out は、 DocTestRunner.run()に渡された出力関数です。

run(test, compileflags=None, out=None, clear_globs=True)

testDocTest オブジェクト)の例を実行し、ライター関数 out を使用して結果を表示します。

例は、名前空間test.globsで実行されます。 clear_globs がtrue(デフォルト)の場合、この名前空間はテストの実行後にクリアされ、ガベージコレクションに役立ちます。 テストの完了後に名前空間を調べたい場合は、 clear_globs = False を使用してください。

compileflags は、例を実行するときにPythonコンパイラーが使用する必要のあるフラグのセットを提供します。 指定しない場合、デフォルトで globs に適用されるfuture-importフラグのセットになります。

各例の出力は、 DocTestRunner の出力チェッカーを使用してチェックされ、結果はDocTestRunner.report_*()メソッドによってフォーマットされます。

summarize(verbose=None)

このDocTestRunnerによって実行されたすべてのテストケースの要約を出力し、名前付きタプル TestResults(failed, attempted)を返します。

オプションの verbose 引数は、要約の詳細度を制御します。 詳細度が指定されていない場合は、 DocTestRunner の詳細度が使用されます。


OutputCheckerオブジェクト

class doctest.OutputChecker

doctestの例からの実際の出力が期待される出力と一致するかどうかを確認するために使用されるクラス。 OutputChecker は、2つのメソッドを定義します。 check_output()は、指定された出力のペアを比較し、一致する場合はTrueを返します。 output_difference()は、2つの出力の違いを説明する文字列を返します。

OutputChecker は、次のメソッドを定義します。

check_output(want, got, optionflags)

例からの実際の出力( got )が期待される出力( want )と一致する場合は、Trueを返します。 これらの文字列は、同一である場合は常に一致すると見なされます。 ただし、テストランナーが使用しているオプションフラグによっては、いくつかの不正確な一致タイプも考えられます。 オプションフラグの詳細については、セクションオプションフラグを参照してください。

output_difference(example, got, optionflags)

特定の例( example )の期待される出力と実際の出力( got )の違いを説明する文字列を返します。 optionflags は、 wantgot を比較するために使用されるオプションフラグのセットです。


デバッグ

Doctestは、doctestの例をデバッグするためのいくつかのメカニズムを提供します。

  • いくつかの関数は、doctestを実行可能なPythonプログラムに変換します。これは、Pythonデバッガー pdb で実行できます。

  • DebugRunner クラスは、 DocTestRunner のサブクラスであり、最初に失敗した例の例外を発生させ、その例に関する情報が含まれています。 この情報を使用して、サンプルの事後デバッグを実行できます。

  • DocTestSuite()によって生成された unittest ケースは、 unittest.TestCase によって定義された debug()メソッドをサポートします。

  • doctestの例で pdb.set_trace()の呼び出しを追加すると、その行が実行されたときにPythonデバッガーにドロップします。 次に、変数の現在の値などを調べることができます。 たとえば、a.pyに次のモジュールdocstringだけが含まれているとします。

    """
    >>> def f(x):
    ...     g(x*2)
    >>> def g(x):
    ...     print(x+3)
    ...     import pdb; pdb.set_trace()
    >>> f(3)
    9
    """

    次に、インタラクティブなPythonセッションは次のようになります。

    >>> import a, doctest
    >>> doctest.testmod(a)
    --Return--
    > <doctest a[1]>(3)g()->None
    -> import pdb; pdb.set_trace()
    (Pdb) list
      1     def g(x):
      2         print(x+3)
      3  ->     import pdb; pdb.set_trace()
    [EOF]
    (Pdb) p x
    6
    (Pdb) step
    --Return--
    > <doctest a[0]>(2)f()->None
    -> g(x*2)
    (Pdb) list
      1     def f(x):
      2  ->     g(x*2)
    [EOF]
    (Pdb) p x
    3
    (Pdb) step
    --Return--
    > <doctest a[2]>(1)?()->None
    -> f(3)
    (Pdb) cont
    (0, 3)
    >>>

doctestをPythonコードに変換し、場合によってはデバッガーで合成されたコードを実行する関数:

doctest.script_from_examples(s)

例を含むテキストをスクリプトに変換します。

引数 s は、doctestの例を含む文字列です。 文字列はPythonスクリプトに変換され、 s のdoctestの例は通常のコードに変換され、その他はすべてPythonコメントに変換されます。 生成されたスクリプトは文字列として返されます。 例えば、

import doctest
print(doctest.script_from_examples(r"""
    Set x and y to 1 and 2.
    >>> x, y = 1, 2

    Print their sum:
    >>> print(x+y)
    3
"""))

表示:

# Set x and y to 1 and 2.
x, y = 1, 2
#
# Print their sum:
print(x+y)
# Expected:
## 3

この関数は、他の関数(以下を参照)によって内部的に使用されますが、インタラクティブなPythonセッションをPythonスクリプトに変換する場合にも役立ちます。

doctest.testsource(module, name)

オブジェクトのdoctestをスクリプトに変換します。

引数 module は、モジュールオブジェクト、またはモジュールの点線の名前であり、doctestが対象となるオブジェクトが含まれています。 引数 name は、対象のdoctestを持つオブジェクトの(モジュール内の)名前です。 結果は、上記の script_from_examples()で説明されているように、Pythonスクリプトに変換されたオブジェクトのdocstringを含む文字列です。 たとえば、モジュールa.pyに最上位関数f()が含まれている場合、

import a, doctest
print(doctest.testsource(a, "a.f"))

関数f()のdocstringのスクリプトバージョンを出力し、doctestをコードに変換し、残りをコメントに配置します。

doctest.debug(module, name, pm=False)

オブジェクトのdoctestをデバッグします。

module および name 引数は、上記の関数 testsource()の場合と同じです。 名前付きオブジェクトのdocstring用に合成されたPythonスクリプトが一時ファイルに書き込まれ、そのファイルがPythonデバッガー pdb の制御下で実行されます。

module.__dict__の浅いコピーは、ローカル実行コンテキストとグローバル実行コンテキストの両方に使用されます。

オプションの引数 pm は、事後デバッグを使用するかどうかを制御します。 pm の値がtrueの場合、スクリプトファイルは直接実行され、デバッガーは、未処理の例外を発生させてスクリプトが終了した場合にのみ関与します。 含まれている場合は、 pdb.post_mortem()を介して事後デバッグが呼び出され、未処理の例外からトレースバックオブジェクトが渡されます。 pm が指定されていないか、falseの場合、スクリプトは、適切な exec()呼び出しを pdb.run()に渡すことにより、デバッガーの下で最初から実行されます。

doctest.debug_src(src, pm=False, globs=None)

文字列でdoctestをデバッグします。

これは、上記の関数 debug()に似ていますが、doctestの例を含む文字列が、 src 引数を介して直接指定される点が異なります。

オプションの引数 pm は、上記の関数 debug()と同じ意味です。

オプションの引数 globs は、ローカル実行コンテキストとグローバル実行コンテキストの両方として使用する辞書を提供します。 指定されていない場合、またはNoneの場合、空の辞書が使用されます。 指定した場合、辞書の浅いコピーが使用されます。

DebugRunner クラス、およびそれが発生する可能性のある特別な例外は、テストフレームワークの作成者にとって最も重要であり、ここでのみスケッチします。 詳細については、ソースコード、特に DebugRunner のdocstring(doctestです!)を参照してください。

class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)

DocTestRunner のサブクラスで、障害が発生するとすぐに例外が発生します。 予期しない例外が発生した場合、 UnexpectedException 例外が発生し、テスト、例、および元の例外が含まれます。 出力が一致しない場合、 DocTestFailure 例外が発生し、テスト、例、および実際の出力が含まれます。

コンストラクターのパラメーターとメソッドについては、セクション Advanced APIDocTestRunner のドキュメントを参照してください。

DebugRunner インスタンスによって発生する可能性のある2つの例外があります。

exception doctest.DocTestFailure(test, example, got)
DocTestRunner によって発生した例外で、doctestの例の実際の出力が期待される出力と一致しなかったことを通知します。 コンストラクター引数は、同じ名前の属性を初期化するために使用されます。

DocTestFailure は、次の属性を定義します。

DocTestFailure.test
例が失敗したときに実行されていた DocTest オブジェクト。
DocTestFailure.example
失敗した
DocTestFailure.got
例の実際の出力。
exception doctest.UnexpectedException(test, example, exc_info)
DocTestRunner によって発生した例外で、doctestの例で予期しない例外が発生したことを通知します。 コンストラクター引数は、同じ名前の属性を初期化するために使用されます。

UnexpectedException は、次の属性を定義します。

UnexpectedException.test
例が失敗したときに実行されていた DocTest オブジェクト。
UnexpectedException.example
失敗した
UnexpectedException.exc_info
sys.exc_info()によって返される、予期しない例外に関する情報を含むタプル。


Soapbox

冒頭で述べたように、 doctest は、次の3つの主要な用途に成長しました。

  1. docstringの例を確認しています。
  2. 回帰試験。
  3. 実行可能なドキュメント/リテラシーテスト。

これらの用途にはさまざまな要件があり、それらを区別することが重要です。 特に、ドキュメント文字列をあいまいなテストケースで埋めると、ドキュメントが不適切になります。

docstringを作成するときは、docstringの例を慎重に選択してください。 これには学ぶ必要のある芸術があります—最初は自然ではないかもしれません。 例は、ドキュメントに真の価値を追加する必要があります。 良い例は、多くの場合、多くの言葉に値するものです。 注意深く行うと、例はユーザーにとって非常に貴重であり、年月が経ち状況が変化するにつれて、何度もそれらを収集するのにかかる時間を回収できます。 doctest の例の1つが、「無害な」変更後に機能しなくなる頻度には、まだ驚いています。

Doctestは、特に説明文を読み飛ばさない場合に、回帰テストのための優れたツールにもなります。 散文と例をインターリーブすることにより、実際にテストされているものとその理由を追跡することがはるかに簡単になります。 テストが失敗した場合、良い散文は問題が何であるか、そしてそれがどのように修正されるべきかを理解することをはるかに簡単にすることができます。 コードベースのテストで広範なコメントを書くことができるのは事実ですが、そうするプログラマーはほとんどいません。 多くの人が、代わりにdoctestアプローチを使用すると、はるかに明確なテストにつながることを発見しました。 おそらくこれは、doctestを使用すると、コードを書くよりも散文を書くのが少し簡単になり、コードにコメントを書くのが少し難しくなるためです。 それだけではありません。doctestベースのテストを作成するときの自然な態度は、ソフトウェアの優れた点を説明し、例を挙げて説明したいということです。 これにより、当然、最も単純な機能で始まるテストファイルが作成され、論理的に複雑化やエッジケースに進みます。 一見ランダムに見える機能の孤立したビットをテストする孤立した機能のコレクションではなく、一貫した物語が結果です。 それは異なる態度であり、異なる結果を生み出し、テストと説明の区別を曖昧にします。

回帰テストは、専用のオブジェクトまたはファイルに限定するのが最適です。 テストを整理するためのいくつかのオプションがあります。

  • インタラクティブな例としてテストケースを含むテキストファイルを作成し、 testfile()または DocFileSuite()を使用してファイルをテストします。 これは推奨されますが、最初からdoctestを使用するように設計された、新しいプロジェクトで行うのが最も簡単です。
  • 名前付きトピックのテストケースを含む、単一のdocstringで構成される_regrtest_topicという名前の関数を定義します。 これらの機能は、モジュールと同じファイルに含めることも、別のテストファイルに分割することもできます。
  • 回帰テストのトピックからテストケースを含むドキュメント文字列への__test__辞書マッピングを定義します。

モジュールにテストを配置すると、モジュール自体がテストランナーになることができます。 テストが失敗した場合、問題をデバッグしている間、テストランナーが失敗したdoctestのみを再実行するように手配できます。 このようなテストランナーの最小限の例を次に示します。

if __name__ == '__main__':
    import doctest
    flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
    if len(sys.argv) > 1:
        name = sys.argv[1]
        if name in globals():
            obj = globals()[name]
        else:
            obj = __test__[name]
        doctest.run_docstring_examples(obj, globals(), name=name,
                                       optionflags=flags)
    else:
        fail, total = doctest.testmod(optionflags=flags)
        print("{} failures out of {} tests".format(fail, total))

脚注

1
期待される出力と例外の両方を含む例はサポートされていません。 一方がどこで終わり、もう一方がどこから始まるかを推測しようとすると、エラーが発生しやすくなり、テストが混乱します。