Pythonの特定のテストとデバッグのメカニズムについて学びましょう。
PythonのDoctestsは関数のテストケースであり、関数が意図したとおりに動作しているかどうかを検証するために使用します。
Pythonのdocstringって何?
doctestsに進む前に、docstringについて学ぶ必要があります。
- docstringsはトリプルクォートで囲まれたオプションの文字列で、関数を宣言するときに最初に記述されます。
- Docstringsは、関数を説明するために使われます。関数が何をするのか、どのように動作するのか、引数の数、返すオブジェクトの種類などを書くことができるのです。
これらはすべて、プログラマに関数の目的を説明するものです。
プログラマは __doc__
属性を使用して関数の docstring にアクセスすることができます。
ある数値の階乗を表示する関数を例にとってみましょう。
def factorial(num):
"""
A function that returns the factorial of a given number.
No. of arguments: 1, Integer
Returns: Integer
"""
res = 1
for i in range ( 1 , num + 1 ):
res * = i
print (res)
|
ご覧のように、関数を宣言した直後、何かをする前に、関数を説明する文字列をトリプルクォートで囲んで書いています。
この文字列がその関数のドキュメントとなり、 __doc__
属性にアクセスすると、この文字列が返されます。
では、それをやってみましょう。
print (factorial.__doc__)
|
出力です。
A function that returns the factorial of a given number.
No. of arguments: 1, Integer
Returns: Integer
docstring が何であるかがわかったので、次は doctests に進みましょう。
Pythonのdoctestsって何?
先ほど説明したように、Pythonのdoctestsはdocstringの中に書かれたテストケースのことです。
今回の例では、5の階乗は120になるので、 factorial(5)
を呼べば 120
と表示され、同様に、 factorial(0)
を呼べば 1
と表示されます。
これらは関数に対して検証可能なテストケースとなり、そのために以下のような構文でdocstringに記述します。
def factorial(num):
"""
A function that returns the factorial of a given number.
No. of arguments: 1, Integer
Returns: Integer
>>> factorial(5)
120
>>> factorial(0)
1
"""
res = 1
for i in range ( 1 , num + 1 ):
res * = i
print (res)
|
Pythonのシェルを思い出してください。
シェルでは、3つの角括弧(>>>
)の後にすべてのコードを記述し、エンターキーを押すとすぐにコードが実行されます。
つまり、Pythonのシェルで factorial(5)
を呼び出すと、上のdocstringに書いたとおりのコードになります。
このようにdocstringで指定することで、Pythonに上の行がシェルで factorial(5)
を実行した後に期待される出力であることを伝えています。
同様にその下には factorial(0)
の期待される出力を正確に書いています。
doctestsは空白やタブに敏感なので、結果として欲しいものを正確に書く必要があることに注意してください。
また、間違った入力の結果として関数が返すかもしれない例外やエラーも指定することができます。
さて、私たちの関数にいくつかのdoctestが書き込まれたので、それらを使って関数が正しく動くかどうかチェックしてみましょう。
Pythonで成功したDoctests
import doctest
doctest.testmod(name = 'factorial' , verbose = True )
|
Pythonでdoctestsを使う方法です。
doctestというモジュールをインポートして、その
testmod` という関数を使います。
出力はこのようになります。
Trying: factorial( 5 )
Expecting: 120
ok Trying: factorial( 0 )
Expecting: 1
ok 1 items had no tests:
factorial
1 items passed all tests:
2 tests in factorial.factorial
2 tests in 2 items.
2 passed and 0 failed.
Test passed. TestResults(failed = 0 , attempted = 2 )
|
見てわかるように、これはすべてのテストケースを実行し、実際の出力が期待される出力と一致するかどうかをチェックします。
最後に、テストの結果が表示され、プログラマはこの関数がどのように動作しているかを分析することができます。
もしテストケースが失敗した場合は、期待される出力の後に正確な出力が表示され、最後に失敗したテストケースの数が指定されます。
PythonのDoctestsの失敗例
Pythonで失敗することが分かっているdoctestを作ってみましょう。
def factorial(num):
"""
A function that returns the factorial of a given number.
No. of arguments: 1, Integer
Returns: Integer
>>> factorial(5)
120
>>> factorial(0)
1
>>> factorial(2)
Two
"""
res = 1
for i in range ( 1 , num + 1 ):
res * = i
print (res)
import doctest
doctest.testmod(name = 'factorial' , verbose = True )
|
3番目のdoctestでは、2
を送っても決してTwo
は出力されないので、その出力を見てみましょう。
Trying: factorial( 5 )
Expecting: 120
ok Trying: factorial( 0 )
Expecting: 1
ok Trying: factorial( 2 )
Expecting: Two
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
File "__main__" , line 13 , in factorial.factorial
Failed example: factorial( 2 )
Expected: Two
Got: 2
1 items had no tests:
factorial
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1 items had failures:
1 of 3 in factorial.factorial
3 tests in 2 items.
2 passed and 1 failed.
* * * Test Failed * * * 1 failures.
TestResults(failed = 1 , attempted = 3 )
|
3つ目のテストケースは失敗し、モジュールはどのように失敗したかを正確に出力しました。
そして最後に、3つのテストケースが試行され、1つが失敗したことがわかります。
PythonでDoctestsを使う?
PythonのDoctestは、期待される出力を念頭に置いて関数を作成するときに使用されることを意図しています。
もし、何かと一緒に呼び出すと正確に何かを表示する関数が必要なら、doctestでそれを指定し、最後にdoctestモジュールですべてのテストケースを一度に実行することができ、その関数がどのように動作したかを確認することができます。
挙げられたテストケースは、まさに期待通りのものでなければなりません。
もし、どれかが失敗したら、それは修正すべき関数のバグを示しています。
完成品のドテストは必ず成功させなければならない。
すべてのテストケースを書くことはできませんが、大きなプロジェクトでは、0、9999999、-1、”banana “など、予期せぬ入力の結果失敗しそうなものを書いておくとよいでしょう。
まとめ
この記事では、Pythonのdoctestsとは何か、どのように書くか、どのように使うか、そしていつ使うかについて勉強しました。
doctest がプログラマのためのテストメカニズムであり、テストケースを簡単に書くことができることを説明しました。
あなたが何かを学んで、また別のチュートリアルでお会いできることを願っています。