Python Doctestの基本的な使い方:コードのテストとドキュメントを同時に!


 

Pythonで開発をしていると、書いたコードが期待通りに動くかを確認するための「テスト」は非常に重要です。しかし、テストコードを別途書くのは手間がかかるもの。そこで役立つのがDoctestです。Doctestは、Pythonのドキュメント文字列(Docstring)の中にテストケースを直接記述できる便利な機能です。これにより、ドキュメントが常に最新のコードと同期していることを保証し、テストとドキュメント作成の二重のメリットを得られます。


 

Doctestとは?

 

Doctestは、Pythonの標準ライブラリに含まれるモジュールで、Docstring内に書かれた対話型Pythonセッションの例をテストとして実行します。これにより、コードの機能と使用例がドキュメントとして分かりやすく記述され、かつそのドキュメントが実際に動くコードと一致しているかを自動的に検証できます。

Docstringの中に、Pythonの対話型シェルで実行するような形式(>>> で始まる行)でコードと期待される出力を記述するだけです。


 

Doctestの基本的な書き方と実行方法

 

 

1. Docstringにテストを記述する

 

テストしたい関数やクラスのDocstring内に、Pythonインタプリタでの対話形式を模倣してテストケースを記述します。

Python
 
def add(a, b):
    """
    2つの数値を加算して返します。

    >>> add(1, 2)
    3
    >>> add(5, 0)
    5
    >>> add(-1, 1)
    0
    """
    return a + b

上記の例では、add 関数のDocstring内に3つのテストケースが記述されています。

  • >>> add(1, 2) の後には期待される出力 3 を記述します。

  • >>> で始まる行がテストの入力、その次の行が期待される出力です。

  • 出力がない場合は、何も記述しません。

 

2. Doctestを実行する

 

Doctestを実行する方法はいくつかありますが、ここでは基本的な2つの方法を紹介します。

 

方法1: スクリプト内で実行する

 

テストを記述したPythonファイルの末尾に、以下のコードを追加します。

Python
 
# test_example.py
def add(a, b):
    """
    2つの数値を加算して返します。

    >>> add(1, 2)
    3
    >>> add(5, 0)
    5
    >>> add(-1, 1)
    0
    """
    return a + b

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

このファイルを保存し、コマンドラインから実行します。

Bash
 
python test_example.py

テストがすべて成功した場合、何も出力されません。失敗した場合は、どのテストが失敗したかの詳細が表示されます。

 

方法2: コマンドラインから実行する

 

Pythonのdoctestモジュールを直接実行し、テストしたいファイルを指定することもできます。

Bash
 
python -m doctest your_module_name.py

例えば、上記のtest_example.pyをテストするには、以下のコマンドを実行します。

Bash
 
python -m doctest test_example.py

 

Doctestの高度な使い方と注意点

 

 

意図的な失敗と例外のテスト

 

エラーが発生するケースもDoctestでテストできます。Pythonのトレースバック(エラーメッセージ)の一部を記述することで、期待される例外が正しく発生するかを確認できます。

Python
 
def divide(a, b):
    """
    2つの数値を割り算して結果を返します。

    >>> divide(10, 2)
    5.0
    >>> divide(10, 0)
    Traceback (most recent call last):
    ...
    ZeroDivisionError: division by zero
    """
    return a / b

Traceback (most recent call last): の後には、省略記号 ... を使うことで、トレースバックの詳細な内容が一致しているかどうかを厳密に検証せずに、特定の例外が発生したことだけを確認できます。

 

出力順序の無視(ELLIPSISオプション)

 

辞書の出力など、順序が保証されない出力をテストする場合、ELLIPSIS オプションを使用すると、... で指定した部分を無視して比較できます。

Python
 
def create_dict(key, value):
    """
    指定されたキーと値を持つ辞書を作成します。

    >>> create_dict("name", "Alice") # doctest: +ELLIPSIS
    {'name': 'Alice'}
    """
    return {key: value}

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True) # verbose=Trueで詳細なテスト結果を表示

 

スペースの無視(NORMALIZE_WHITESPACEオプション)

 

出力の空白文字(スペース、タブ、改行)の差異を無視して比較したい場合は、NORMALIZE_WHITESPACE オプションを使用します。

Python
 
def format_text(text):
    """
    テキストを整形して返します。

    >>> format_text("Hello  World") # doctest: +NORMALIZE_WHITESPACE
    "Hello World"
    """
    return " ".join(text.split())

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

 

Doctestのメリットとデメリット

 

 

メリット

 

  • テストとドキュメントの同期: コードの挙動とドキュメントが常に一致していることを保証できます。

  • シンプルな記述: 追加のテストフレームワークを学ぶ必要がなく、Pythonの対話型シェルに慣れていれば簡単に記述できます。

  • 可読性の向上: コードの使用例がDocstringに直接記述されるため、他の開発者が関数やクラスの使い方を理解しやすくなります。

  • 手軽なテスト: 小規模な関数やモジュールの動作確認に非常に適しています。

 

デメリット

 

  • 複雑なテストには不向き: データベース操作や外部API連携など、複雑なセットアップが必要なテストには向いていません。

  • 出力の厳密な一致: デフォルトでは、Docstringに記述された出力と実際の出力が完全に一致する必要があります。

  • テストコードの散在: テストケースが複数のDocstringに散らばるため、テスト全体の見通しが悪くなる場合があります。


 

まとめ

 

Doctestは、PythonのDocstringを活用して手軽にテストを記述できる強力なツールです。特に、シンプルで単一の機能を果たす関数やクラスのテストに非常に有効です。コードの品質向上とドキュメントの正確性維持のために、ぜひDoctestをあなたの開発プロセスに取り入れてみてください。より複雑なテストには、unittestpytestといった専用のテストフレームワークの利用も検討しましょう。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座