python3.7 unittestトラブルメモ
python3.7 unittestトラブルメモ
※python 3.7時点での方法,今後のアップデートで変わる可能性あり.
unittestがうまく動作しなかったときの対処メモ(大体パス通せば解決するはず). 今回はパスを通さず手っ取り早くテストできる状態にする.
以下のファイル構成とする.
project/ test_target.py test/ test_1.py \__init__.py
ポイントとしては, - テストパッケージが名前空間パッケージ(namespace package)になっていない(init.pyがあるか) - テストファイルを単体実行する場合,テスト対象モジュールのパスが見えるか
解決早見表
trouble | solve |
---|---|
module = __import__(module_name) ModuleNotFoundError: No module named 'test.test_1' | 使用コマンドが名前空間パッケージに対応していないので__init__.py を追加する |
import test_target ModuleNotFoundError: No module named 'test_target' | (親にある)テスト対象モジュールを読めていないのでsys.path.append() でパスを追加 or python unittest -m でunittestをモジュール呼び出しスクリプト実行する. |
環境
- Windows10
- python 3.7.0
unittestの使い方
新しい機能やオプションの確認はドキュメントにある.
また具体例はDive Into Python3でもトピックがある.
テストファイルの実行方法は4種類ほど(オプションを含めたら無数にあるが)
python -m unittest test.test_1
:モジュール名の指定python -m unittest test/test_1.py
:テストファイル名の指定(上と同じ処理)python -m unittest discover -s test
:テストファイルをまとめて実行python test/test_1.py
:テストファイル自体の実行- IDE(ex. VSCode)の拡張機能を利用
モジュール読み込みではテストクラス(テストスイート)やテスト関数のみの実行ができる.
python -m unittest test.test_1.TestClass`:テストクラスの実行 python -m unittest test.test_1.TestClass.test_func`:TestClass内のtest_funcメソッドの実行
unittest注意点
モジュール名の指定だけでなくファイル名の指定もできる
python unittest -m
の際,モジュール名しか指定できないという記述がよくあるが,ファイル名の指定もできる.
ドキュメントの最初のほうにも載っている.
python unittest -m test.test_1 上と同じ python unittest -m test/test_1.py
unittestでの名前空間パッケージの扱い
python -m unittest discover
では名前空間パッケージ(__init__.py
なし)に対応しているが,通常の使用では対応していないことに注意.
なので,以下の構成だと
''' project/ test_target.py test/(名前空間パッケージ) test_1.py '''
discover
は問題ないが
python -m unittest discover -s test test ok
モジュール名(ファイル名)呼び出しではモジュールが見つからない.
python -m unittest test.test_1 module = __import__(module_name) ModuleNotFoundError: No module named 'test.test_1'
__init__.py
を置いて通常のパッケージ
にすれば問題なくテストできる.
テストファイル単体実行時の注意
unittestを介さず直接テストファイルを実行できる.
python test/test_1.py
ただこのときテスト対象モジュールが階層上にあると,python3ではそのファイルにはアクセスできないのでエラーValueError: attempted relative import beyond top-level package
になる.
例えば,テストファイルtest_1.py
を以下にすると読み込めずエラーになる.
import test_target
ValueError: attempted relative import beyond top-level package
この場合,sys.path
にテスト対象モジュールの絶対パス(相対パスは有効にならない)を追加すれば解決する.(ただし,テストファイル毎)に必要になり面倒になる.
絶対パスの求め方はpathlib
を使うと動的に求められる.
import sys import pathlib path = pathlib.Path('__file__') path /= '../' # 1つ上の階層を指す sys.path.append(str(path.resolve())) import test_target