実践・中級問題チェック

問題 35 /40

次のnormalize_name()関数をdoctestでテストする場合、★★★に入れる正しい記述はどれか。

normalize.py
-------------------------------
def normalize_name(name):
    return name.strip().lower()

★★★
-------------------------------

選択 1

"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

if __name__ == '__main__':
    import doctest
    doctest.testfile('normalize.txt')

選択 2

"""
名前文字列を正規化する関数です

normalize_name('  Tanaka  ') => 'tanaka'
normalize_name(' SUZUKI') => 'suzuki'
"""

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

選択 3

"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

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

選択 4

"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

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

解説

選択肢3が正解です。

問題文のnormalize_name()関数は、前後の空白を削除して、大文字を小文字に変換する関数です。

def normalize_name(name):
    return name.strip().lower()

これをdoctestでテストします。


【選択肢1】
"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

if __name__ == '__main__':
    import doctest
    doctest.testfile('normalize.txt')

誤った記述です。

最後のtestfile()は、外部のテキストファイルに書かれたdoctestを実行するための関数です。モジュール内のdocstringのテストは、testfile()ではなくtestmod()を使います。


【選択肢2】
"""
名前文字列を正規化する関数です

normalize_name('  Tanaka  ') => 'tanaka'
normalize_name(' SUZUKI') => 'suzuki'
"""

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

誤った記述です。

関数呼び出しと期待値の間で「=>」を使っています。doctestは「>>>」に続けて関数呼び出しを記述し、その下に期待値を記述します。


【選択肢3】
"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

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

正しい記述です。

「>>>」に続く関数呼び出しの下に期待値を記述し、testmod()でモジュール内のdocstringテストを実行しています。

次のnormalize.pyをテストをする場合は、コマンドラインで「python normalize.py」と入力して実行します。

normalize.py
-------------------------------
def normalize_name(name):
    return name.strip().lower()

"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

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

"""で囲むdocstringは、このように関数の外に書くか、def normalize_name(name):の直下に書きます。

実行すると、Pythonが変数__name__に__main__を代入し、if __name__ == '__main__':がTrueになり、doctest.testmod()が実行されます。

テストが成功すると、コマンドラインには何も表示されません。

doctest.testmod()を、doctest.testmod(verbose=True)とすれば、次のような詳細が表示されます。

Trying:
    normalize_name('  Tanaka  ')
Expecting:
    'tanaka'
ok
Trying:
    normalize_name(' SUZUKI')
Expecting:
    'suzuki'
ok
1 items had no tests:
    __main__
1 items passed all tests:
   2 tests in __main__.normalize_name
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

docstringに、次のような誤った期待値を記述していた場合は、詳細が表示されます。

>>> normalize_name('  Tanaka  ')
'tanakA'


◾️ verbose=Trueなし
*************************************
File "normalize.py", line 5, in __main__.normalize_name
Failed example:
    normalize_name('  Tanaka  ')
Expected:
    'tanakA'
Got:
    'tanaka'
*************************************
1 items had failures:
   1 of   2 in __main__.normalize_name
***Test Failed*** 1 failures.


◾️ verbose=Trueあり
Trying:
    normalize_name('  Tanaka  ')
Expecting:
    'tanakA'
*************************************
File "__main__", line 5, in __main__.normalize_name
Failed example:
    normalize_name('  Tanaka  ')
Expected:
    'tanakA'
Got:
    'tanaka'
Trying:
    normalize_name(' SUZUKI')
Expecting:
    'suzuki'
ok
1 items had no tests:
    __main__
*************************************
1 items had failures:
   1 of   2 in __main__.normalize_name
2 tests in 2 items.
1 passed and 1 failed.
***Test Failed*** 1 failures.


【選択肢4】
"""
名前文字列を正規化する関数です

>>> normalize_name('  Tanaka  ')
'tanaka'
>>> normalize_name(' SUZUKI')
'suzuki'
"""

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

誤った記述です。

最後でdoctest.run()を使っていますが、doctestモジュールにrun()という関数は存在しません。


(公式書籍 p.366-367)