概要
monkeypatch.setattr を使う場合に少し注意が必要です
環境
- macOS 11.7.2
- python 3.10.2
- pytest 7.2.0
ディレクトリ構成
tree -a test module
test
├── __init__.py
└── test_user.py
module
├── __init__.py
├── profile.py
└── user.py
サンプルコード
User クラスが Profile クラスをカプセル化しています
この Profile クラスに monkeypatch 当てることを想定します
- vim module/profile.py
class Profile():
def __init__(self, lang):
self.lang = lang
- vim module/user.py
from module.profile import Profile
class User():
def __init__(self, name, age):
self.name = name
self.age = age
self.profile = Profile("ruby")
def show(self):
print(self.name)
print(self.age)
print(self.profile.lang)
テストコード
- vim test/test_user.py
from module.user import User
def test_show():
user = User("hawksnowlog", 10)
user.show()
上記が通常のテストコードになります
これで実行すると Profile.lang は「ruby」が表示されます
このテストコードに Profile に対して monkeypatch を当ててみます
from module.user import User
class DummyProfile():
def __init__(self, _):
self.lang = "python"
def test_show(monkeypatch):
# monkeypatch.setattr("module.profile.Profile", DummyProfile) # これだとうまく動かない
monkeypatch.setattr("module.user.Profile", DummyProfile)
user = User("hawksnowlog", 10)
user.show()
これで pipenv run pytest -s
を実行すると Profile.lang が python になっているのが確認できると思います
ポイント
monkeypatch.setattr する際のモジュールですが本来であれば実際に存在するモジュールパスを指定したくなりますが setattr を引数 2 つで指定する場合は モジュールを使用する側のパスを指定 します
これが謎な仕様ではあるのですがこうすることでパッチを当てられます
引数 3 つで setattr する場合には存在するクラスやモジュールのパスを指定するのですが 2 つの場合だけ使用する側のパスを指定する必要があるようです
0 件のコメント:
コメントを投稿