僕とコードとブルーハワイ

omega (@equal_001) の日記

python の doctest

26.3. doctest — 対話的な実行例をテストする — Python 3.5.1 ドキュメント

そういえば使ったことがなかったので触ってみたのと、使い道とかの個人的な感想メモ。

pythonでテストするときはunittest, pytest, pylintあたりしか使ったことがなかった。


demo.py

"""
>>> test("omega")
'Hello, omega!'
"""

def test(name):
    return "Hello, {}!".format(name)

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

実行結果

~$ python demo.py -v  # -vすると実行詳細がみれる

"""
>>> test("omega")
'Hello, omega!'
"""

def test(name):
    return "Hello, {}!".format(name)

if __name__ == "__main__":
    import doctest
    doctest.testmod()
OMEGA:~$ python test.py
OMEGA:~$ python test.py -v
Trying:
    test("omega")
Expecting:
    'Hello, omega!'
ok
1 items had no tests:
    __main__.test
1 items passed all tests:
   1 tests in __main__
1 tests in 2 items.
1 passed and 0 failed.
Test passed.

こんな感じ。
ちなみにdocstringの気分で書いて、Expectingにシングルクォートで囲まないHello, omega!を記述していたら見事にfailedになった。

上記ではdemo,pyでdoctestをimportしてるけど、コマンドラインからdemo,pyを単体モジュールとしてimportしてテスト実行することもできる。

~$ python -m doctest -v demo.py

テストしたい内容が増えたりするとpythonファイルが肥大化するので、そういうときは testmod()の代わりにtestfile()と使うとよい。
doctest.testfile("test_list.txt") と書いてtest_list.txtの中にTrying/Expectingをガシガシ書いていけばいい。

test_list.txtの中身はこんな感じ。

>>> from demo import test
>>> test("omega")
'Hello, omega!'

なおこれもコマンドラインから実行できる。

~$ python -m doctest -v test_list.txt

例外について思ったところ

例外については公式ドキュメントにも書いてあった。
トレースバックを貼ればいいだけらしいけど、filepathとか変更されやすいものだったりrandom的なもので毎回値が変化するようなものには向いていない。
そもそもあまり例外でテストするのは良くないと思うけど。
例外に関して評価される部分としては、例外の型からそれ以降だけらしい。
以下の場合、最初の二行はスルーされる。

Traceback (most recent call last):
    ... 
ValueError: multi
    line
detail

やっぱり例外を扱うのはよろしくないと思う。なってほしい結果の一例としてのwikiのようなものくらいのほうが良いと思う。

単体テストAPI

多分使わないと思うけど、doctestをunittest.TestSuite に変換することができる機能を持っている。

デバッグ

使わないと思うけど使いそうなところを挙げるとpdbが使える、 TestCaseのdebug()が使える。以上。

感想

doctestはexampleとして記述しておくのが良いのかなと思った。私の中では今のところ、docstringをより良いものにするためのという位置付け。
あと、モジュールの方針・本当に実現したい機能を思い出させてくれるものとしても良いかも。
ガシガシコード書いてると、よく方向性見失ったりするので、、