doctest --- 対話型の Python の例をテストする

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


doctest モジュールは Python の対話セッションに見えるテキストを探し、そのセッションを実行して記載どおりに動作するか検証します。 主な使い方は次のとおりです。

  • モジュールの docstring (ドキュメンテーション文字列) 中にある対話実行例のすべてが書かれている通りに動作するか検証することで、docstring の内容が最新かどうかチェックする。

  • テストファイルやテストオブジェクト中の対話実行例が期待通りに動作するかを検証することで、回帰テストを実現します。

  • 入出力例を豊富に使ったパッケージのチュートリアルドキュメントが書けます。入出力例と解説文のどちらに注目するかによって、ドキュメントは「読めるテスト」にも「実行できるドキュメント」にもなります。

以下に完全かつ短い実行例を示します:

"""
これは "example" モジュールです。

example モジュールは factorial() という関数を一つ提供します。
例えば、

>>> factorial(5)
120
"""

def factorial(n):
    """0 以上の整数 n の階乗を返します。

    >>> [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

    浮動小数点数でも階乗を求められますが、その値は厳密に整数でなければなりません:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    また、極端に大きな値も使えません:
    >>> 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:  # 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 test in __main__
   6 tests in __main__.factorial
7 tests in 2 items.
7 passed.
Test passed.
$

doctest を役立てるには、これだけ知っていれば十分です!さっそく使ってみましょう。 以下の節では詳細を説明します。 Python 標準のテストスイートやライブラリには、doctest の例が数多くあります。 特に参考になる例は、標準のテストファイル Lib/test/test_doctest/test_doctest.py にあります。

Added in version 3.13: 出力はデフォルトで色付きになり、環境変数で制御できます。

簡単な利用法: docstring 中の実行例をチェックする

doctest を試す簡単な方法 (とはいえ、いつもそうする必要はないのですが) は、各モジュール M の最後を、以下のようにして締めくくることです:

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

こうすると、 doctest は M 中の docstring を検査します。

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

python M.py

docstring に書かれた実行例の実行が失敗しない限り、何も表示されません。失敗すると、失敗した実行例と、その原因が (場合によっては複数) 標準出力に印字され、最後に ***Test Failed*** N failures. という行を出力します。ここで、N は失敗した実行例の数です。

一方、-v スイッチをつけて走らせると:

python M.py -v

実行を試みたすべての実行例について詳細に報告し、最後に各種まとめを行った内容が標準出力に印字されます。

verbose=True を testmod() に渡せば、詳細報告 (verbose) モードを強制できます。また、 verbose=False にすれば禁止できます。どちらの場合にも、 testmod() は sys.argv 上のスイッチを調べません。(したがって、 -v をつけても効果はありません)。

testmod() をコマンドラインから簡単に実行する方法もあります。 コマンドラインでの使用 節を参照してください。

testmod() の詳しい情報は 基本 API 節を参照してください。

簡単な利用法: テキストファイル中の実行例をチェックする

doctest のもう一つの簡単な用途は、テキストファイル中にある対話実行例に対するテストです。これには testfile() 関数を使います:

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

この短いスクリプトは、 example.txt というファイルの中に入っている対話モードの Python 操作例すべてを実行して、その内容を検証します。ファイルの内容は一つの巨大な docstring であるかのように扱われます; ファイルが Python プログラムである必要はありません!例えば、 example.txt には以下のような内容が入っているとします:

``example`` モジュール
=====================

``factorial`` の使い方
---------------------

これは reStructuredText 形式のテキストファイルの例です。
まず ``example`` モジュールから ``factorial`` をインポートします:

    >>> from example import factorial

次に、使ってみましょう:

    >>> 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() と同じ書式で標準出力に書き出されます。

デフォルトでは、 testfile() は自分自身を呼び出したモジュールのあるディレクトリを探します。その他の場所にあるファイルを見に行くように testfile() に指示するためのオプション引数についての説明は 基本 API 節を参照してください。

testmod() と同様に testfile() の冗長性 (verbosity) はコマンドラインスイッチ -v またはオプションのキーワード引数 verbose によって指定できます。

testfile() をコマンドラインから簡単に実行する方法もあります。 コマンドラインでの使用 節を参照してください。

testfile() の詳細は 基本 API 節を参照してください。

コマンドラインでの使用

doctest モジュールはコマンドラインからスクリプトとして実行できます。

python -m doctest [-v] [-o OPTION] [-f] file [file ...]
-v, --verbose

試したすべての実行例の詳細な報告を標準出力に表示し、最後に各種の結果をまとめます。

python -m doctest -v example.py

こうすると example.py を単体モジュールとしてインポートして、それに対して testmod() を実行します。このファイルがパッケージの一部で他のサブモジュールをそのパッケージからインポートしている場合はうまく動かないことに注意してください。

ファイル名が .py で終わっていない場合、doctest は代わりに testfile() で実行すべきだと判断します。

python -m doctest -v example.txt
-o, --option <option>

オプションフラグで doctest のさまざまな動作を制御できます。 オプションフラグ 節を参照してください。

Added in version 3.4.

-f, --fail-fast

-o FAIL_FAST の短縮形です。

Added in version 3.4.

doctest のからくり

この節では、doctest のからくり: どの docstring を見に行くのか、どのように対話実行例を見つけ出すのか、どんな実行コンテキストを使うのか、例外をどう扱うか、上記の振る舞いを制御するためにどのようなオプションフラグを使うか、について詳しく吟味します。こうした情報は、doctest に対応した実行例を書くために必要な知識です; 書いた実行例に対して実際に doctest を実行する上で必要な情報については後続の節を参照してください。

どの docstring が検証されるのか?

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

テストをモジュールに含めつつ、ヘルプテキストには表示したくない場合もあります。 その場合、テストを docstring に含めることはできません。 Doctest はモジュールレベルの変数 __test__ を探し、それを使って他のテストを見つけます。 M.__test__ が存在する場合、その値は辞書でなければならず、各項目は名前 (文字列) を関数オブジェクト、クラスオブジェクト、または文字列に対応付けます。 M.__test__ から見つかった関数やクラスの docstring が検索され、文字列は docstring として扱われます。 出力では、M.__test__ のキー K は M.__test__.K という名前で表示されます。

例えば、次のコードブロックを example.py の先頭に置きます。

__test__ = {
    'numbers': """
>>> factorial(6)
720

>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
}

example.__test__["numbers"] の値は docstring として扱われ、その中のテストがすべて実行されます。 辞書の値には関数、クラスオブジェクト、モジュールを指定することもできます。 その場合、doctest はそれらから docstring を再帰的に探し、見つかった docstring からテストを検索します。

検索中に見つかったクラスも同様に再帰的に検索が行われ、クラスに含まれているメソッドおよびネストされたクラスについて docstring のテストが行われます。

注釈

doctest が自動的に見つけられるのは、モジュールレベルまたは他のクラス内で定義されたクラスと関数だけです。

関数内にネストされたクラスや関数は、外側の関数が呼ばれたときにしか存在しないため、見つけることができません。 見つけられるようにするには、関数の外で定義してください。

docstring 内の実行例をどのように認識するのか?

ほとんどの場合、対話コンソールセッション上でのコピー/ペーストはうまく動作します。とはいえ、 doctest は特定の Python シェルの振る舞いを正確にエミュレーションしようとするわけではありません。

>>> # コメントは無視されます
>>> x = 12
>>> x
12
>>> if x == 13:
...     print("yes")
... else:
...     print("no")
...     print("NO")
...     print("NO!!!")
...
no
NO
NO!!!
>>>

コードを含む最後の '>>> ' または '... ' 行の直下に期待する出力結果が置かれます。(出力結果がもしあれば) それは次の '>>> ' 行か、すべて空白文字の行まで続きます。

詳細事項:

  • 期待する出力結果には、空白だけの行が入っていてはなりません。そのような行は期待する出力結果の終了を表すと見なされるからです。もし期待する出力結果の内容に空白行が入っている場合には、空白行が入るべき場所すべてに <BLANKLINE> を入れてください。

  • 全てのタブ文字は 8 カラムのタブ位置でスペースに展開されます。テスト対象のコードが作成した出力にあるタブは変更されません。出力例にあるどんなタブも展開 される ので、コードの出力がハードタブを含んでいた場合、 doctest が通るには NORMALIZE_WHITESPACE オプションか directive を有効にするしかありません。そうする代わりに、テストが出力を読み取りテストの一部として期待される値と正しく比較するように、テストを書き直すこともできます。このソース中のタブの扱いは試行錯誤の結果であり、タブの扱いの中で最も問題の起きにくいものだということが分かっています。タブの扱いについては、独自の DocTestParser クラスを実装して、別のアルゴリズムを使うこともできます。

  • 標準出力への出力は取り込まれますが、標準エラーは取り込まれません (例外発生時のトレースバックは別の方法で取り込まれます)。

  • 対話セッションにおいて、バックスラッシュを用いて次の行に続ける場合や、その他の理由でバックスラッシュを用いる場合、raw docstring を使ってバックスラッシュを入力どおりに扱わせるようにしなければなりません:

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

    そうしない場合は、バックスラッシュは文字列の一部として解釈されます。例えば、上の \n は改行文字として解釈されてしまいます。それ以外の方法では、doctest にあるバックスラッシュを二重にする (そして raw string を使わない) という方法もあります:

    >>> 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 のあるテストが残した状態によって別のテストが偶然成功するのを防ぎます。 したがって、実行例では M のトップレベルで定義された名前や、実行中の docstring 内でそれ以前に定義された名前を自由に使えます。 他の docstring 内で定義された名前は参照できません。

testmod() や testfile() に globs=your_dict を渡し、自前の辞書を実行コンテキストとして使うこともできます。

例外はどう扱えばよいか?

トレースバックが実行例によって生成される唯一の出力なら問題ありません。単にトレースバックを貼り付けてください。[1] トレースバックには、頻繁に変更されがちな情報 (例えばファイルパスや行番号など) が入っているものなので、これは受け入れるテスト結果に柔軟性を持たせようと doctest が苦労している部分の一つです。

簡単な例を示しましょう:

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

この doctest は、 ValueError が送出され、その詳細情報が list.remove(x): x not in list である場合に成功します。

例外が発生したときの期待する出力はトレースバックヘッダから始まっていなければなりません。トレースバックの形式は以下の二通りの行のいずれかで、実行例の最初の行と同じインデントでなければりません:

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 個) 並べたり、Monty Python の寸劇をインデントして書き写したりしてもかまいません。

以下の詳細はずっと覚えておく必要はないのですが、一度目を通しておいてください:

  • doctest は期待する出力の出所が print 文なのか例外なのかを推測できません。したがって、例えば期待する出力が ValueError: 42 is prime であるような実行例は、 ValueError が実際に送出された場合と、万が一期待する出力と同じ文字列を print した場合の両方で成功してしまいます。現実的には、通常の出力がトレースバックヘッダから始まることはないので、実際に問題になることはないでしょう。

  • トレースバックスタック (がある場合) の各行は、実行例の最初の行よりも深くインデントされているか、または 英数文字以外で始まっていなければなりません。トレースバックヘッダ以後に現れる行のうち、インデントが等しく英数文字で始まる最初の行は例外の詳細情報が書かれた行とみなされるからです。もちろん、本物のトレースバックでは正しく動作します。

  • doctest のオプション IGNORE_EXCEPTION_DETAIL を指定した場合、最も左端のコロン以後の全ての内容と、例外名の中の全てのモジュール情報が無視されます。

  • 対話シェルでは、 SyntaxError の場合にトレースバックヘッダが省略されることがあります。しかし doctest にとっては、例外を例外でないものと区別するためにトレースバックヘッダが必要です。そこで、トレースバックヘッダを省略するような SyntaxError をテストする必要があるというごく稀なケースでは、実行例にトレースバックヘッダを手作業で追加する必要があるでしょう。

  • 一部の例外では、Python は ^ マーカとチルダを使ってエラーの位置を示します。

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ~~^~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

    例外の型と詳細情報の前にエラー位置を示す行がくるため、doctest はこの行を調べません。例えば、以下の例では、間違った場所に ^ マーカを入れても成功してしまいます:

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ^~~~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

オプションフラグ

doctest の振る舞いは、数多くのオプションフラグによって様々な側面から制御されています。フラグのシンボル名はモジュールの定数として提供され、 ビット単位論理和 でつないで様々な関数に渡すことができます。シンボル名は doctest directives でも使用でき、doctest コマンドラインインターフェースに -o を通して与えることができます。

最初に説明するオプション群は、テストのセマンティクスを決めます。すなわち、実際にテストを実行したときの出力と実行例中の期待する出力とが一致しているかどうかを doctest がどのように判断するかを制御します:

doctest.DONT_ACCEPT_TRUE_FOR_1

デフォルトでは、期待する出力ブロックに単に 1 だけが入っており、実際の出力ブロックに 1 または True だけが入っていた場合、これらの出力は一致しているとみなされます。 0 と False の場合も同様です。 DONT_ACCEPT_TRUE_FOR_1 を指定すると、こうした値の読み替えを行いません。デフォルトの挙動で読み替えを行うのは、最近の Python で多くの関数の戻り値型が整数型からブール型に変更されたことに対応するためです; 読み替えを行う場合、"通常の整数" の出力を期待する出力とするような doctest も動作します。このオプションはそのうちなくなるでしょうが、ここ数年はそのままでしょう。

doctest.DONT_ACCEPT_BLANKLINE

デフォルトでは、期待する出力ブロックに <BLANKLINE> だけの入った行がある場合、その行は実際の出力における空行に一致するようになります。完全な空行を入れてしまうと期待する出力がそこで終わっているとみなされてしまうため、期待する出力に空行を入れたい場合にはこの方法を使わなければなりません。 DONT_ACCEPT_BLANKLINE を指定すると、 <BLANKLINE> の読み替えを行わなくなります。

doctest.NORMALIZE_WHITESPACE

このフラグを指定すると、連続する空白 (空白と改行文字) は互いに等価であるとみなします。期待する出力における任意の空白列は実際の出力における任意の空白と一致します。デフォルトでは、空白は厳密に一致しなければなりません。 NORMALIZE_WHITESPACE は、期待する出力の内容が非常に長いために、ソースコード中でその内容を複数行に折り返して書きたい場合に特に便利です。

doctest.ELLIPSIS

このフラグを指定すると、期待する出力中の省略記号マーカ (...) が実際の出力中の任意の部分文字列と一致するようになります。部分文字列は行境界にわたるものや空文字列を含みます。したがって、このフラグを使うのは単純な内容を対象にする場合にとどめましょう。複雑な使い方をすると、正規表現に .* を使ったときのように "しまった、マッチしすぎた! (match too much!)" と驚くことになりかねません。

doctest.IGNORE_EXCEPTION_DETAIL

このフラグを指定すると、例外を期待する doctest は、期待した型の例外が送出されれば成功します。 詳細 (メッセージと例外の完全修飾名) が一致していなくてもかまいません。

例えば、ValueError: 42 を期待する実行例は、実際に送出された例外が ValueError: 3*14 でも成功しますが、代わりに TypeError などが送出されると失敗します。 例外クラスの前に付いた完全修飾名も無視します。 この部分は Python の実装やバージョン、使用するコードやライブラリによって異なることがあります。 したがって、このフラグを指定すると、次の 3 通りはいずれも成功します。

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

>>> raise Exception('message')
Traceback (most recent call last):
builtins.Exception: message

>>> raise Exception('message')
Traceback (most recent call last):
__main__.Exception: message

ELLIPSIS を使って例外メッセージの詳細を無視することもできますが、その場合はモジュール名の有無や完全一致するかどうかによってテストが失敗する可能性があります。

バージョン 3.2 で変更: doctest モジュールの IGNORE_EXCEPTION_DETAIL フラグが、 テストされている例外を含むモジュールの名前を無視するようになりました。

doctest.SKIP

このフラグを指定すると、実行例は一切実行されません。こうした機能は doctest の実行例がドキュメントとテストを兼ねていて、ドキュメントのためには含めておかなければならないけれどチェックされなくても良い、というような文脈で役に立ちます。例えば、実行例の出力がランダムであるとか、テストドライバーには利用できないリソースに依存している場合などです。

SKIP フラグは一時的に実行例を"コメントアウト"するのにも使えます。

doctest.COMPARISON_FLAGS

上記の比較フラグすべての論理和をとったビットマスクです。

二つ目のオプション群は、テストの失敗を報告する方法を制御します:

doctest.REPORT_UDIFF

このオプションを指定すると、期待する出力および実際の出力が複数行になるときにテストの失敗結果を unified diff 形式を使って表示します。

doctest.REPORT_CDIFF

このオプションを指定すると、期待する出力および実際の出力が複数行になるときにテストの失敗結果を context diff 形式を使って表示します。

doctest.REPORT_NDIFF

このオプションを指定すると、期待する出力と実際の出力との間の差分を difflib.Differ を使って算出します。使われているアルゴリズムは有名な ndiff.py ユーティリティと同じです。これは、行単位の差分と同じように行内の差分にマーカをつけられるようにする唯一の手段です。例えば、期待する出力のある行に数字の 1 が入っていて、実際の出力には l が入っている場合、不一致の起きているカラム位置を示すキャレットの入った行が一行挿入されます。

doctest.REPORT_ONLY_FIRST_FAILURE

このオプションを指定すると、各 doctest で最初にエラーの起きた実行例だけを表示し、それ以後の実行例の出力を抑制します。これにより、正しく書かれた実行例が、それ以前の実行例の失敗によっておかしくなってしまった場合に、 doctest がそれを報告しないようになります。とはいえ、最初に失敗を引き起こした実行例とは関係なく誤って書かれた実行例の報告も抑制してしまいます。 REPORT_ONLY_FIRST_FAILURE を指定した場合、実行例がどこかで失敗しても、それ以後の実行例を続けて実行し、失敗したテストの総数を報告します; 出力が抑制されるだけです。

doctest.FAIL_FAST

このオプションを指定すると、最初に実行例が失敗した時点で終了し、残りの実行例を実行しません。つまり、報告される失敗の数はたかだか 1 つになります。最初の失敗より後の例はデバッグ出力を生成しないため、このフラグはデバッグの際に有用でしょう。

doctest.REPORTING_FLAGS

上記のエラー報告に関するフラグすべての論理和をとったビットマスクです。

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

doctest.register_optionflag(name)

名前 name の新たなオプションフラグを作成し、作成されたフラグの整数値を返します。 register_optionflag() は OutputChecker や DocTestRunner をサブクラス化して、その中で新たに作成したオプションをサポートさせる際に使います。 register_optionflag() は以下のような定形文で呼び出さなければなりません:

MY_FLAG = register_optionflag('MY_FLAG')

ディレクティブ (Directives)

doctest ディレクティブを使うと、個々の実行例の オプションフラグ を変更できます。 doctest ディレクティブは、実行例のソースコードの後ろに置く特殊な Python コメントです:

directive:             "#" "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 ディレクティブは、その実行例だけの doctest の振る舞いを変えます。ある特定の挙動を有効にしたければ + を、無効にしたければ - を使います。

例えば、以下のテストは成功します:

>>> print(list(range(20)))  # doctest: +NORMALIZE_WHITESPACE
[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)))  # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]

複数のディレクティブは、一つの物理行の中にコンマで区切って指定できます:

>>> print(list(range(20)))  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

一つの実行例中で複数のディレクティブコメントを使った場合、それらは組み合わされます:

>>> print(list(range(20)))  # doctest: +ELLIPSIS
...                         # doctest: +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

この実行例で分かるように、実行例にはディレクティブだけを含む ... 行を追加することができます。この書きかたは、実行例が長すぎるためにディレクティブを同じ行に入れると収まりが悪い場合に便利です:

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

フォルトではすべてのオプションが無効になっており、ディレクティブは特定の実行例だけに影響を及ぼすので、通常意味があるのは有効にするためのオプション (+ のついたディレクティブ) だけです。とはいえ、doctest を実行する関数はオプションフラグを指定してデフォルトとは異なった挙動を実現できるので、そのような場合には - を使った無効化オプションも意味を持ちます。

警告

doctest は期待する出力との厳密な一致を求めます。 1 文字でも一致しなければテストは失敗します。 Python が出力について何を保証し、何を保証しないのかを知るにつれて、意外に思うこともあるでしょう。 例えば、集合を表示するときに要素が特定の順序で表示されることは保証されていないため、次のようなテストは

>>> foo()
{"spam", "eggs"}

は失敗するかもしれないのです! 回避するには

>>> foo() == {"spam", "eggs"}
True

とするのが一つのやり方です。別のやり方は

>>> d = sorted(foo())
>>> d
['eggs', 'spam']

他のやり方もありますが、あとは自分で考えてみてください。

以下のように、オブジェクトアドレスを埋め込むような結果を print するのもよくありません :

>>> id(1.0)  # いつか必ず失敗します
7948648
>>> class C: pass
>>> C()  # インスタンスのデフォルトの repr() にはアドレスが含まれます
<C object at 0x00AC18F0>

ELLIPSIS ディレクティブを使うと、上のような例をうまく解決できます:

>>> C()  # doctest: +ELLIPSIS
<C object at 0x...>

浮動小数点数も、プラットフォームによって出力がわずかに変わることがあります。 Python は一部の浮動小数点演算をプラットフォームの C ライブラリに任せており、その品質には大きな違いがあるためです。

>>> 1000**0.1  # 危険
1.9952623149688797
>>> round(1000**0.1, 9) # より安全
1.995262315
>>> print(f'{1000**0.1:.4f}') # さらに安全
1.9953

I/2.**J の形式になる数値はどのプラットフォームでもうまく動作するので、私はこの形式の数値を生成するように doctest の実行例を工夫しています:

>>> 3./4  # 完全に安全
0.75

単純な分数は人間にとっても理解しやすく、良いドキュメントを書くために役に立ちます。

基本 API

関数 testmod() と testfile() は、基本的な用途の大半に十分な、doctest の簡単なインターフェースを提供します。 この 2 つの関数の平易な入門については、簡単な利用法: docstring 中の実行例をチェックする 節と 簡単な利用法: テキストファイル中の実行例をチェックする 節を参照してください。

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_relative が True (デフォルト) の場合、filename は OS に依存しないモジュールの相対パスになります。デフォルトでは、このパスは関数 testfile() を呼び出しているモジュールからの相対パスになります; ただし、package 引数を指定した場合には、パッケージからの相対になります。OS への依存性を除くため、filename ではパスを分割する文字に / を使わなければならず、絶対パスにしてはなりません (パス文字列を / で始めてはなりません)。

  • module_relative が False の場合、filename は OS 依存のパスを示します。パスは絶対パスでも相対パスでもかまいません; 相対パスにした場合、現在の作業ディレクトリを基準に解決します。

オプション引数 name には、テストの名前を指定します; デフォルトの場合や None を指定した場合、os.path.basename(filename) になります。

オプション引数 package には、Python パッケージを指定するか、モジュール相対のファイル名の場合には相対の基準ディレクトリとなる Python パッケージの名前を指定します。パッケージを指定しない場合、関数を呼び出しているモジュールのディレクトリを相対の基準ディレクトリとして使います。module_relative を False に指定している場合、package を指定するとエラーになります。

オプション引数 globs には辞書を指定します。この辞書は、実行例を実行する際のグローバル変数として用いられます。doctest はこの辞書の浅いコピーを生成するので、実行例は白紙の状態からスタートします。デフォルトの場合や None を指定した場合、新たな空の辞書になります。

オプション引数 extraglobs には辞書を指定します。この辞書は、実行例を実行する際にグローバル変数にマージされます。マージは dict.update() のように振舞います: globs と extraglobs との間に同じキー値がある場合、両者を合わせた辞書中には extraglobs の方の値が入ります。デフォルト、または None であるとき、追加のグローバル変数は使われません。この仕様は、パラメータ付きで doctest を実行するという、やや進んだ機能です。例えば、一般的な名前を使って基底クラス向けに doctest を書いておき、その後で辞書で一般的な名前からテストしたいサブクラスへの対応付けを行う辞書を extraglobs に渡して、様々なサブクラスをテストできます。

オプション引数 verbose が真の場合、様々な情報を出力します。偽の場合にはテストの失敗だけを報告します。デフォルトの場合や None を指定した場合、sys.argv に '-v' を指定しない限りこの値は真になりません。

オプション引数 report が真の場合、テストの最後にサマリを出力します。それ以外の場合には何も出力しません。verbose モードの場合、サマリには詳細な情報を出力しますが、そうでない場合にはサマリはとても簡潔になります (実際には、すべてのテストが成功した場合には何も出力しません)。

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

オプション引数 raise_on_error の値はデフォルトでは偽です。真にすると、最初のテスト失敗や予期しない例外が起きたときに例外を送出します。このオプションを使うと、失敗の原因を検死デバッグ (post-mortem debug) できます。デフォルトの動作では、実行例の実行を継続します。

オプション引数 parser には、 DocTestParser (またはそのサブクラス) を指定します。このクラスはファイルから実行例を抽出するために使われます。デフォルトでは通常のパーザ (DocTestParser()) です。

オプション引数 encoding にはファイルをユニコードに変換する際に使われるエンコーディングを指定します。

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__ 内の実行例からテストを開始します。

辞書 m.__test__ が存在する場合、そこから到達可能な実行例もテストします。 m.__test__ は名前 (文字列) を関数、クラス、文字列に対応付けます。 関数やクラスでは docstring から実行例を検索し、文字列は docstring とみなして直接検索します。

モジュール m に属するオブジェクトにつけられた docstring のみを検索します。

(failure_count, test_count) を返します。

オプション引数 name には、モジュールの名前を指定します。デフォルトの場合や None を指定した場合には、m.__name__ を使います。

オプション引数 exclude_empty はデフォルトでは偽になっています。この値を真にすると、doctest を持たないオブジェクトを考慮から外します。デフォルトの設定は依存のバージョンとの互換性を考えたハックであり、doctest.master.summarize と testmod() を合わせて利用しているようなコードでも、テスト実行例を持たないオブジェクトから出力を得るようにしています。新たに追加された DocTestFinder のコンストラクタの exclude_empty はデフォルトで真になります。

オプション引数 extraglobs, verbose, report, optionflags, raise_on_error, および globs は上で説明した testfile() の引数と同じです。ただし、 globs のデフォルト値は m.__dict__ になります。

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

オブジェクト f に関連付けられた実行例をテストします。 f は文字列、モジュール、関数、またはクラスオブジェクトです。

引数 globs に辞書を指定すると、その浅いコピーを実行コンテキストに使います。

オプション引数 name はテスト失敗時のメッセージに使われます。デフォルトの値は 'NoName' です。

オプション引数 verbose の値を真にすると、テストが失敗しなくても出力を生成します。デフォルトでは、実行例のテストに失敗したときのみ出力を生成します。

オプション引数 compileflags には、実行例を実行するときに Python バイトコードコンパイラが使うフラグを指定します。デフォルトの場合や None を指定した場合、フラグは globs 内にある future 機能セットに対応したものになります。

オプション引数 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 インスタンスを生成するための主な関数は二つあります:

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

単一または複数のテキストファイルに入っている doctest 形式のテストを、 unittest.TestSuite インスタンスに変換します。

返された unittest.TestSuite は unittest フレームワークで実行するもので、各ファイルの対話実行例を実行します。 各ファイルが個別の単体テストとして実行され、ファイル内の各実行例が サブテスト として実行されます。 ファイル内の実行例が一つでも失敗すると、生成された単体テストも失敗します。 失敗やエラーのトレースバックには、テストを含むファイルの名前と行番号 (おおよその行番号になることもあります) が含まれます。 ファイル内の実行例がすべてスキップされると、生成された単体テストもスキップとして扱われます。

関数には、テストを行いたい一つまたは複数のファイルへのパスを (文字列で) 渡します。

DocFileSuite() には、キーワード引数でオプションを指定できます:

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

  • module_relative が True (デフォルト) の場合、paths 中のファイル名は OS に依存しないモジュールの相対パスになります。デフォルトでは、このパスは呼び出し元のモジュールのディレクトリからの相対パスになります; ただし、package 引数を指定した場合には、パッケージからの相対になります。OS への依存性を除くため、各ファイル名はパスを分割するのに / 文字を使わなければならず、絶対パスにしてはなりません (パス文字列を / で始めてはなりません)。

  • module_relative が False の場合、paths 内の各ファイル名は OS 依存のパスを示します。 パスは絶対パスでも相対パスでもかまいません; 相対パスにした場合、現在の作業ディレクトリを基準に解決します。

オプション引数 package には、Python パッケージを指定するか、モジュール相対のファイル名の場合には相対の基準ディレクトリとなる Python パッケージの名前を指定します。パッケージを指定しない場合、関数を呼び出しているモジュールのディレクトリを相対の基準ディレクトリとして使います。module_relative を False に指定している場合、package を指定するとエラーになります。

省略可能な引数 setUp には、テストスイートの準備を行う関数を指定します。 この関数は各ファイルのテストを実行する前に呼び出されます。 setUp 関数には DocTest オブジェクトが渡されます。 渡されたテストの globs 属性を使うと、テストのグローバル変数にアクセスできます。

省略可能な引数 tearDown には、テストスイートの後片付けを行う関数を指定します。 この関数は各ファイルのテストを実行した後に呼び出されます。 tearDown 関数には DocTest オブジェクトが渡されます。 渡されたテストの globs 属性を使うと、テストのグローバル変数にアクセスできます。

オプション引数 globs は辞書で、テストのグローバル変数の初期値が入ります。この辞書は各テストごとに新たにコピーして使われます。デフォルトでは globs は空の新たな辞書です。

オプション引数 optionflags には、テストを実行する際にデフォルトで適用される doctest オプションを OR で結合して指定します。 オプションフラグ 節を参照してください。結果レポートに関するオプションを指定するより適切な方法は下記の set_unittest_reportflags() の説明を参照してください。

オプション引数 parser には、 DocTestParser (またはそのサブクラス) を指定します。このクラスはファイルから実行例を抽出するために使われます。デフォルトでは通常のパーザ (DocTestParser()) です。

オプション引数 encoding にはファイルをユニコードに変換する際に使われるエンコーディングを指定します。

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

バージョン 3.15 で変更: 各実行例を サブテスト として実行します。

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

doctest のテストを unittest.TestSuite に変換します。

返された unittest.TestSuite は unittest フレームワークで実行するもので、モジュール内の各 doctest を実行します。 各 docstring が個別の単体テストとして実行され、docstring 内の各実行例が サブテスト として実行されます。 doctest が一つでも失敗すると、生成された単体テストも失敗します。 失敗やエラーのトレースバックには、テストを含むファイルの名前と行番号 (おおよその行番号になることもあります) が含まれます。 docstring 内の実行例がすべてスキップされると、生成された単体テストもスキップとして扱われます。

オプション引数 module には、テストしたいモジュールの名前を指定します。module にはモジュールオブジェクトまたは (ドット表記の) モジュール名を指定できます。module を指定しない場合、この関数を呼び出しているモジュールになります。

オプション引数 globs は、テスト用のグローバル変数の初期値を含む辞書です。 各テストに対してこの辞書の新しいコピーが作成されます。 デフォルトでは、globs はモジュールの __dict__ です。

オプション引数 extraglobs には追加のグローバル変数セットを指定します。この変数セットは globs に統合されます。デフォルトでは、追加のグローバル変数はありません。

オプション引数 test_finder は、モジュールから doctest を抽出するための DocTestFinder オブジェクト (またはその代替となるオブジェクト) です。

オプション引数 setUp、tearDown、optionflags は上記の DocFileSuite() と同じですが、準備と後片付けの関数は docstring ごとに呼び出されます。

この関数は testmod() と同じ検索方法を使います。

バージョン 3.5 で変更: module がドキュメンテーション文字列を含まない場合には、 DocTestSuite() は ValueError を送出するのではなく空の unittest.TestSuite を返します。

バージョン 3.15 で変更: 各実行例を サブテスト として実行します。

内部では、DocTestSuite() は doctest.DocTestCase インスタンスから unittest.TestSuite を作成します。 DocTestCase は unittest.TestCase のサブクラスです。 DocTestCase は実装の詳細にあたるため、ここでは説明しませんが、そのコードを読むと unittest との統合の詳しい仕組みが分かります。

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

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

このため、doctest は次の関数によって、unittest との連携専用の doctest 報告フラグも提供します。

doctest.set_unittest_reportflags(flags)

使用する doctest の報告フラグを設定します。

引数 flags はオプションフラグの ビット単位論理和 を取ります。 オプションフラグ 節を参照してください。「レポートフラグ」しか使えません。

これはモジュール全体の設定で、以後 unittest モジュールで実行するすべての doctest に影響します。 DocTestCase の runTest() メソッドは、DocTestCase インスタンスの作成時にそのテストケースに指定されたオプションフラグを調べます。 報告フラグが指定されていない場合 (通常はこの使い方を想定しています)、doctest の unittest 用報告フラグをオプションフラグに ビット単位論理和で加え、doctest の実行用に作成した DocTestRunner インスタンスに渡します。 DocTestCase インスタンスの作成時に報告フラグが一つでも指定されている場合、doctest の unittest 用報告フラグは無視されます。

この関数は、関数を呼び出す前に有効になっていた unittest レポートフラグの値を返します。

拡張 API

基本 API は、doctest を使いやすくするための簡単なラッパであり、柔軟性があってほとんどのユーザの必要を満たしています; とはいえ、もっとテストをきめ細かに制御したい場合や、doctest の機能を拡張したい場合、拡張 API (advanced API) を使わなければなりません。

拡張 API は、doctest ケースから抽出した対話モードでの実行例を記憶するための二つのコンテナクラスを中心に構成されています:

  • Example: 1つの Python 文 と、その期待する出力をペアにしたもの。

  • DocTest: Example の集まり。通常一つの docstring やテキストファイルから抽出されます。

その他に、doctest の実行例を検索、構文解析、実行、チェックするための処理クラスが以下のように定義されています:

  • DocTestFinder: 与えられたモジュールからすべての docstring を検索し、 DocTestParser を使って対話モードでの実行例が入ったすべての docstring から DocTest を生成します。

  • DocTestParser: (オブジェクトの docstring 等の) 文字列から DocTest オブジェクトを生成します。

  • DocTestRunner: DocTest 内の実行例を実行し、 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 インスタンス中の同名の属性の初期化に使われます。

DocTest では、以下の属性を定義しています。これらの変数はコンストラクタで初期化されます。直接変更してはなりません。

examples

対話モードにおける実行例それぞれをエンコードしていて、テストで実行される、 Example オブジェクトからなるリストです。

globs

実行例を実行する名前空間 (いわゆるグローバル変数) です。このメンバは、名前から値への対応付けを行っている辞書です。実行例が名前空間に対して (新たな変数を束縛するなど) 何らかの変更を行った場合、 globs への反映はテストの実行後に起こります。

name

DocTest を識別する名前の文字列です。通常、この値はテストを取り出したオブジェクトかファイルの名前になります。

filename

この DocTest の抽出元のファイル名です。 ファイル名が不明な場合、または DocTest をファイルから抽出したのではない場合は None です。

lineno

filename 中で DocTest のテスト実行例が始まっている行の行番号で、行番号が利用できなければ None です。行番号は、ファイルの先頭を 0 として数えます。

docstring

テストを取り出した docstring 自体を現す文字列です。docstring 文字列を得られない場合や、文字列からテスト実行例を取り出したのでない場合には None になります。

Example オブジェクト

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

ひとつの Python 文と、それに対する期待する出力からなる、単一の対話的モードの実行例です。コンストラクタの引数は Example インスタンス中の同名の属性の初期化に使われます。

Example では、以下の属性を定義しています。これらの変数はコンストラクタで初期化されます。直接変更してはなりません。

source

実行例のソースコードを含む文字列です。 ソースコードは単一の Python 文で、末尾は常に改行です。 コンストラクタは必要に応じて改行を追加します。

want

実行例のソースコードを実行した際の期待する出力 (標準出力と、例外が生じた場合にはトレースバック) です。 want の末尾は、期待する出力がまったくない場合を除いて常に改行になります。期待する出力がない場合には空文字列になります。コンストラクタは必要に応じて改行を追加します。

exc_msg

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

lineno

この実行例を含む文字列における実行例が始まる行番号です。行番号は文字列の先頭を 0 として数えます。

indent

実行例の入っている文字列のインデント、すなわち実行例の最初のプロンプトより前にある空白文字の数です。

options

オプションフラグを True または False に対応付ける辞書で、この実行例のデフォルトのオプションを上書きするために使われます。 この辞書に含まれないオプションフラグは、DocTestRunner の optionflags で指定されたデフォルト値のままになります。 デフォルトではオプションは設定されていません。

DocTestFinder オブジェクト

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

与えられたオブジェクトについて、そのオブジェクト自身の docstring か、そのオブジェクトに含まれるオブジェクトの docstring から DocTest を抽出する処理クラスです。モジュール、クラス、関数、メソッド、静的メソッド、クラスメソッド、プロパティから DocTest を抽出できます。

オプション引数 verbose を使うと、抽出処理の対象となるオブジェクトを表示できます。デフォルトは False (出力を行わない) です。

オプション引数 parser には、 docstring から DocTest を抽出するのに使う DocTestParser オブジェクト (またはその代替となるオブジェクト) を指定します。

オプション引数 recurse が偽の場合、 DocTestFinder.find() は与えられたオブジェクトだけを調べ、そのオブジェクトに含まれる他のオブジェクトを調べません。

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

DocTestFinder では以下のメソッドを定義しています:

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

obj または obj 内に入っているオブジェクトの docstring 中で定義されている DocTest のリストを返します。

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

オプションのパラメータ module は、指定したオブジェクトを収めているモジュールを指定します。 module を指定しないか、None を指定した場合には、正しいモジュールを自動的に決定しようと試みます。 オブジェクトのモジュールは以下のような役割を果たします:

  • globs を指定していない場合、オブジェクトのモジュールはデフォルトの名前空間になります。

  • 他のモジュールから import されたオブジェクトに対して DocTestFinder が DocTest を抽出するのを避けるために使います。 (module 由来でないオブジェクトを無視します。)

  • オブジェクトの入っているファイル名を調べるために使います。

  • オブジェクトがファイル内の何行目にあるかを調べる手助けにします。

module が False の場合、モジュールを検索しません。 これは主に doctest 自体のテストで使う特殊な機能です。 module が False の場合、または None でモジュールを自動的に見つけられなかった場合、すべてのオブジェクトがその (実在しない) モジュールに属するとみなします。 そのため、内部のすべてのオブジェクトから doctest を再帰的に検索します。

各 DocTest のグローバル変数は、globs と extraglobs を組み合わせて作られます (extraglobs の束縛が globs の束縛を上書きします)。 各 DocTest に対して、グローバル変数の辞書の新しい浅いコピーが作成されます。 globs を指定しない場合、モジュールが指定されていればその __dict__ を、そうでなければ {} を使います。 extraglobs を指定しない場合のデフォルトは {} です。

DocTestParser オブジェクト

class doctest.DocTestParser

対話モードの実行例を文字列から抽出し、それを使って DocTest オブジェクトを生成するために使われる処理クラスです。

DocTestParser では以下のメソッドを定義しています:

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

指定した文字列からすべての doctest 実行例を抽出し、 DocTest オブジェクト内に集めます。

globs、name、filename、lineno は、新しい DocTest オブジェクトの属性です。 詳しくは DocTest のドキュメントを参照してください。

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

指定した文字列からすべての doctest 実行例を抽出し、 Example オブジェクトからなるリストにして返します。各 Example の行番号は 0 から数えます。オプション引数 name はこの文字列につける名前で、エラーメッセージにしか使われません。

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

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

TestResults オブジェクト

class doctest.TestResults(failed, attempted)
failed

失敗したテストの数。

attempted

実行を試みたテストの数。

skipped

スキップしたテストの数。

Added in version 3.13.

DocTestRunner オブジェクト

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

DocTest 内の対話モード実行例を実行し、検証する際に用いられる処理クラスです。

期待する出力と実際の出力は OutputChecker が比較します。 この比較はさまざまなオプションフラグでカスタマイズできます。 詳しくは オプションフラグ 節を参照してください。 オプションフラグだけでは不十分な場合、コンストラクタに OutputChecker のサブクラスを渡して比較をカスタマイズすることもできます。

テストランナーの表示出力は 2 通りの方法で制御できます。 まず、run() に出力用の関数を渡せます。 この関数には、表示する文字列が渡されます。 デフォルトは sys.stdout.write です。 出力を取り込むだけでは不十分な場合、DocTestRunner のサブクラスを作り、report_skip()、report_start()、report_success()、report_unexpected_exception()、report_failure() メソッドをオーバーライドして、表示出力をカスタマイズすることもできます。

オプションのキーワード引数 checker には、 OutputChecker オブジェクト (またはその代替となるオブジェクト) を指定します。このオブジェクトは doctest 実行例の期待する出力と実際の出力との比較を行う際に使われます。

オプションのキーワード引数 verbose は、 DocTestRunner の出すメッセージの冗長性を制御します。 verbose が True の場合、各実行例を実行する都度、その実行例についての情報を出力します。 verbose が False の場合、テストの失敗だけを出力します。 verbose を指定しない場合や None を指定した場合、コマンドラインスイッチ -v を使った場合にのみ verbose 出力を適用します。

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

テストランナーは統計情報を蓄積します。 実行を試みた実行例、失敗した実行例、スキップした実行例の累計は、それぞれ tries、failures、skips 属性でも参照できます。 run() と summarize() メソッドは TestResults インスタンスを返します。

DocTestRunner は以下のメソッドを定義しています。

report_skip(out, test, example)

指定した実行例がスキップされたことを報告します。 このメソッドは DocTestRunner のサブクラスで出力をカスタマイズするために提供されています。 直接呼び出さないでください。

example は処理しようとしている実行例です。 test は example を含むテストです。 out は DocTestRunner.run() に渡された出力用の関数です。

Added in version 3.15.

report_start(out, test, example)

テストランナーが実行例を処理しようとしているときにレポートを出力します。 DocTestRunner の出力をサブクラスでカスタマイズできるようにするためのメソッドです。直接呼び出してはなりません。

example は処理しようとしている実行例です。 test は example を含むテストです。 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)

test (DocTest オブジェクト) 内の実行例を実行し、書き込み用の関数 out で結果を表示します。 TestResults インスタンスを返します。

実行例は名前空間 test.globs の下で実行されます。clear_globs が真 (デフォルト) の場合、名前空間はテストの実行後に消去され、ガベージコレクションを促します。テストの実行完了後にその内容を調べたければ、clear_globs=False としてください。

compileflags には、実行例を実行する際に Python コンパイラに適用するフラグセットを指定します。compileflags を指定しない場合、デフォルト値は globs で適用されている future-import フラグセットになります。

各実行例の出力は DocTestRunner の出力チェッカーで検証され、結果は DocTestRunner.report_*() メソッドで書式化されます。

summarize(verbose=None)

この DocTestRunner が実行したすべてのテストケースの結果をまとめて表示し、TestResults インスタンスを返します。

オプションの verbose 引数を使うと、どのくらいサマリを詳しくするかを制御できます。冗長度を指定しない場合、 DocTestRunner 自体の冗長度を使います。

DocTestParser has the following attributes:

tries

実行を試みた実行例の数。

failures

失敗した実行例の数。

skips

スキップした実行例の数。

Added in version 3.13.

OutputChecker オブジェクト

class doctest.OutputChecker

doctest 実行例を実際に実行したときの出力が期待する出力と一致するかどうかをチェックするために使われるクラスです。 OutputChecker では、与えられた二つの出力を比較して、一致する場合には True を返す check_output() と、二つの出力間の違いを説明する文字列を返す output_difference() の、二つのメソッドがあります。

OutputChecker では以下のメソッドを定義しています:

check_output(want, got, optionflags)

実行例から実際に得られた出力 (got) と、期待する出力 (want) が一致する場合にのみ True を返します。二つの文字列がまったく同一の場合には常に一致するとみなしますが、テストランナーの使っているオプションフラグにより、厳密には同じ内容になっていなくても一致するとみなす場合もあります。オプションフラグについての詳しい情報は オプションフラグ 節を参照してください。

output_difference(example, got, optionflags)

与えられた実行例 (example) の期待する出力と、実際に得られた出力 (got) の間の差異を解説している文字列を返します。optionflags は want と got を比較する際に使われるオプションフラグのセットです。

デバッグ

doctest では、doctest 実行例をデバッグするメカニズムをいくつか提供しています:

  • doctest を実行可能な Python プログラムに変換し、 Python デバッガ pdb で実行できるようにするための関数がいくつかあります。

  • DocTestRunner のサブクラス DebugRunner クラスがあります。このクラスは、最初に失敗した実行例に対して例外を送出します。例外には実行例に関する情報が入っています。この情報は実行例の検死デバッグに利用できます。

  • DocTestSuite() の生成する unittest テストケースは、 debug() メソッドをサポートしています。 debug() は unittest.TestCase で定義されています。

  • pdb.set_trace() を doctest 実行例の中で呼び出しておけば、その行が実行されたときに Python デバッガが組み込まれます。デバッガを組み込んだあとは、変数の現在の値などを調べられます。たとえば、以下のようなモジュールレベルの docstring の入ったファイル a.py があるとします:

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

    対話セッションは以下のようになるでしょう:

    >>> 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 スクリプトに変換したいような場合にも便利でしょう。

doctest.testsource(module, name)

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

引数 module は、対象の doctest を持つオブジェクトを含むモジュールのオブジェクト、またはドット区切りのモジュール名です。 引数 name は、対象の doctest を持つオブジェクトのモジュール内での名前です。 戻り値は、上記の script_from_examples() と同じ方法で、オブジェクトの docstring を Python スクリプトに変換した文字列です。 例えば、モジュール 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 が真の場合、スクリプトファイルは直接実行され、スクリプトが送出した例外が処理されないまま終了した場合にのみデバッガが立ち入ります。その場合、 pdb.post_mortem() によって検死デバッグを起動し、処理されなかった例外から得られたトレースバックオブジェクトを渡します。 pm を指定しないか値を偽にした場合、 pdb.run() に適切な exec() 呼び出しを渡して、最初からデバッガの下でスクリプトを実行します。

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

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

上の debug() に似ていますが、doctest の入った文字列は src 引数で直接指定します。

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

オプション引数 globs には、ローカルおよびグローバルな実行コンテキストの両方に使われる辞書を指定します。globs を指定しない場合や None にした場合、空の辞書を使います。辞書を指定した場合、実際の実行コンテキストには浅いコピーが使われます。

DebugRunner クラス自体や DebugRunner クラスが送出する特殊な例外は、テストフレームワークの作者にとって非常に興味のあるところですが、ここでは概要しか述べられません。詳しくはソースコード、とりわけ DebugRunner の docstring (それ自体 doctest です!) を参照してください:

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

テストの失敗に遭遇するとすぐに例外を送出するようになっている DocTestRunner のサブクラスです。予期しない例外が生じると、 UnexpectedException 例外を送出します。この例外には、テスト、実行例、もともと送出された例外が入っています。期待する出力と実際の出力が一致しないために失敗した場合には、 DocTestFailure 例外を送出します。この例外には、テスト、実行例、実際の出力が入っています。

コンストラクタのパラメータやメソッドについては、 拡張 API 節の DocTestRunner のドキュメントを参照してください。

DebugRunner インスタンスの送出する例外には以下の二つがあります:

exception doctest.DocTestFailure(test, example, got)

doctest 実行例の実際の出力が期待する出力と一致しなかったことを示すために DocTestRunner が送出する例外です。コンストラクタの引数は、インスタンスの同名の属性を初期化するために使われます。

DocTestFailure では以下の属性を定義しています:

DocTestFailure.test

実行例が失敗した時に実行されていた DocTest オブジェクトです。

DocTestFailure.example

失敗した Example オブジェクトです。

DocTestFailure.got

実行例の実際の出力です。

exception doctest.UnexpectedException(test, example, exc_info)

doctest 実行例が予期しない例外を送出したことを示すために DocTestRunner が送出する例外です。コンストラクタの引数は、インスタンスの同名の属性を初期化するために使われます。

UnexpectedException では以下の属性を定義しています:

UnexpectedException.test

実行例が失敗した時に実行されていた DocTest オブジェクトです。

UnexpectedException.example

失敗した Example オブジェクトです。

UnexpectedException.exc_info

予期しない例外についての情報の入ったタプルで、 sys.exc_info() が返すのと同じものです。

アドバイス

導入で述べたように、doctest は主に次の 3 つの用途で使われるようになりました。

  1. docstring 内の実行例をチェックする。

  2. 回帰テストを行う。

  3. 実行可能なドキュメント/読めるテストの実現。

これらの用途にはそれぞれ違った要求があるので、区別して考えるのが重要です。特に、docstring を曖昧なテストケースに埋もれさせてしまうとドキュメントとしては最悪です。

docstring を書くときは、そこに載せる実行例を慎重に選んでください。 これには身につけるべきこつがあり、最初は自然にはできないかもしれません。 実行例はドキュメントに確かな価値を加えるものであるべきです。 よい実行例は、多くの言葉による説明に匹敵することがあります。 注意深く作れば、実行例はユーザーにとって非常に役立ち、年月が過ぎて物事が変わっても、集めるのにかけた時間に何倍もの価値を返してくれるでしょう。 「無害な」はずの変更の後で自分の doctest の実行例が動かなくなることが、今でも驚くほどよくあります。

Doctest は回帰テストの優れたツールにもなります。 説明文を惜しまず書けば、特に役立ちます。 説明文と実行例を交互に記述すると、実際に何を、なぜテストしているのかを把握しやすくなります。 テストが失敗したときにも、よい説明文があれば問題と修正方法が分かりやすくなります。 確かに、コードで書くテストにも詳しいコメントを付けられますが、そうするプログラマーは少数です。 代わりに doctest を使うと、はるかに分かりやすいテストになると感じる人は多くいます。 単に、doctest ではコードよりも説明文が少し書きやすく、コード中ではコメントが少し書きにくいからかもしれません。 私はそれよりも深い理由があると考えています。 doctest ベースのテストを書くときは、ソフトウェアの細かな点を説明し、実行例で示そうという姿勢に自然となります。 すると、最も単純な機能から始まり、複雑な場合や境界条件へと論理的に進むテストファイルになります。 結果として、個々の機能の断片をばらばらにテストする関数の集まりではなく、筋の通った説明ができます。 取り組む姿勢が違うため、テストと説明の区別が薄れるという違った結果を生むのです。

回帰テストは特定のオブジェクトやファイルにまとめておくのがよいでしょう。回帰テストの組み方にはいくつか選択肢があります:

  • テストケースを対話モードの実行例にして入れたテキストファイルを書き、 testfile() や DocFileSuite() を使ってそのファイルをテストします。この方法をお勧めします。最初から doctest を使うようにしている新たなプロジェクトでは、この方法が一番簡単です。

  • _regrtest_topic という名前の関数を定義します。この関数には、あるトピックに対応するテストケースの入った docstring が一つだけ入っています。この関数はモジュールと同じファイルの中にも置けますし、別のテストファイルに分けてもかまいません。

  • 回帰テストのトピックを、テストケースを含む docstring に対応付ける __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(f"{fail} failures out of {total} tests")

脚注