pythonでは、ドキュメントとして書かれたコメントと、実際の動作が一致するか確認する手段として、doctestを標準で提供しています。
題材として、大まかな動作の説明をdocstringに書いた、以下のhoge()という簡単なメソッドを扱います。
# coding:utf-8 # sample.py import re def hoge(line): ''' 指定した文字列から定数名の定義を抽出する # (1)プリプロセッサのマクロ定義名を抽出する >>> from sample import hoge >>> hoge('#define PREPRO_MACRO 33') 'PREPRO_MACRO' # (2)const変数の名前を抽出する >>> hoge('const int const_variable_name = 33;') 'const_variable_name' ''' result = re.search('[\s\t]*#define[\s\t]+([a-zA-Z_0-9]*)', line) if result != None: return result.group(1) result = re.search('[\s\t]*const[\s\t]+[a-zA-Z_0-9]*[\s\t]+([a-zA-Z0-9_]*)[\s\t]+=', line) if result != None: return result.group(1) result = re.search('[\s\t]*constexpr[\s\t]+[a-zA-Z_0-9]*[\s\t]+([a-zA-Z_0-9]*)[\s\t]+=', line) if result != None: return result.group(1) return ''
これを以下のようなコマンドで、doctest上で実行します。
python -m doctest sample.py
すると、doctestはコメント内容に基づき、hoge()を実行して以下の確認を行います。
- 「hoge('#define PREPRO_MACRO 33')」の戻り値が「'PREPRO_MACRO'」であること。
- 「hoge('const int const_variable_name = 33;')」の戻り値が「'const_variable_name'」であること。
たとえば適当なバグをコードに埋め込むと、次のようにコメントの仕様と動作の差異を報告してくれます。
File "sample.py", line 14, in sample.hoge Failed example: hoge('const int const_variable_name = 33;') Expected: 'const_variable_name' Got: ''
このdoctestは外部向けに仕様を解説するコメントの保守に便利です。特にTest as DocumentationやSpecification by Exampleを推進するテストファースト手法を直接的にサポートしてくれます。
カバレッジでコメント解説の十分性を評価
doctestではコードカバレッジの計測も可能です。doctestでのコードカバレッジを見ることで、コメントの解説の十分性を簡易チェックできるようになります。
(あくまで参考指標です。ここで「doctestでカバレッジ100%得られるまでコメントを書くこと」を強制しだすと当然おかしくなります)
例えばcoverage.pyを使う場合、以下のようなコマンドを実行します。
coverage run -m doctest sample.py
すると以下のconstexprについてのコードが実行されていないことがカバレッジレポートで報告されます。それで、該当部分についてのコメントの説明が足りないことに気づけます。
result = re.search('[\s\t]*constexpr[\s\t]+[a-zA-Z_0-9]*[\s\t]+([a-zA-Z_0-9]*)[\s\t]+=', line) if result != None: return result.group(1)