結論
- 直接モジュールの変数を上書きすれば良い
- ただし、importされた時点でそのモジュールの変数として扱われる事に注意
※文字で見ても良くわからないと思うので下記のコードを参照
ケース1(テスト対象に直接変数がimportされている場合)
テスト対象のコード群
# a.py from define import HOGE class TargetClass: def get_hoge(self): return f"aaa_{HOGE}_bbb" # ここのHOGEを入れ替えたい
# define.py HOGE = 'hoge'
ユニットテスト
import a from a import TargetClass def test_hoge(): a.HOGE = 'piyo' # モジュールをインポートしてモジュールの変数を直接入れ替える target_class = TargetClass() assert target_class.get_hoge() == 'aaa_piyo_bbb'
ケース2(テスト対象で使用されている別モジュールで直接変数がimportされている場合)
テスト対象のコード群
# a.py from b import get_hoge class TargetClass: def get_hoge2(self): return f"aaa_{get_hoge()}_bbb"
# b.py from define import HOGE def get_hoge(): return HOGE # ここのHOGEを入れ替えたい
# define.py HOGE = 'hoge'
ユニットテスト
import b from a import TargetClass def test_hoge2(): b.HOGE = 'piyo' # モジュールをインポートしてモジュールの変数を直接入れ替える target_class = TargetClass() assert target_class.get_hoge2() == 'aaa_piyo_bbb'
※結局やっているのはケース1と同じで直接bをインポートして値を入れ替える
経緯とか
- ↑に書いた通りのことをやりたかったが調べ方もわからずハマった
unittest.patch
だと、Mockになってしまうので、違うそうじゃない感。
蛇足
- ケース2のようにできるのであれば、定義の方を変更できそうに見えるが通常はうまくいかない
- 下記のユニットテスト2のように、入れ替えたいモジュール(今回であれば
b
)が呼び出される前であればうまくいくが、一度呼び出すとモジュール内に直接定義されるようで、想定通りにならない
テスト対象コード(ケース2と同じ)
# a.py from b import get_hoge class TargetClass: def get_hoge2(self): return f"aaa_{get_hoge()}_bbb"
# b.py from define import HOGE def get_hoge(): return HOGE # ここのHOGEを入れ替えたい
# define.py HOGE = 'hoge'
ユニットテスト1(うまくいかないケース)
from a import TargetClass import define def test_hoge(): define.HOGE = 'piyo' # 元々定義されている値を入れ替える target_class = TargetClass() assert target_class.get_hoge2() == 'aaa_piyo_bbb' # AssertionError
テストケースの from a import TargetClass
ここで a.py
が読まれて、from b import get_hoge
が読まれて、b.py
の from define import HOGE
まで読まれる。 これにより、b内にHOGEが定義されてしまう。
これにより、テストケース内で define.HOGE
を置き換えても、b.HOGE
は既に定義されているため値が変更されない。
ユニットテスト2(うまくいくがイマイチなケース)
import define define.HOGE = 'piyo' # テストモジュールの先頭でimportした直後に値を変更する from a import TargetClass def test_hoge(): target_class = TargetClass() assert target_class.get_hoge2() == 'aaa_piyo_bbb'
うまく動作するには動作するが、linterに指摘されますし、実際に動かすときには1ファイルのテストだけではないと思われるので、先に実行される他のテストでbがimportされていたら結局同じ事が発生すると思われる。