概要
例えば socket モジュール内のメソッドを monkeypatch したい場合に「なぜか monkeypatch できない」という現象が発生したとします
そんな場合にチェックするべきポイントを紹介します
環境
- macOS 10.15.6
- Python 3.8.5
準備
pipenv install pytest
monkeypatch できないコード
まずは monkeypatch できないコードを紹介します
一見できそうなのですが以下で紹介しているテストコードでテストしようとすると普通に DNS サーバに問い合わせてしまいます
vim app.py
from socket import gethostbyname
def resolve(hostname):
return gethostbyname(hostname)
テストコード
こちらがテストコードです
monkeypatch で socket の gethostbyname をパッチしています
リターンは適当な IP アドレスにしています
import socket
from app import resolve
def test_resolve(monkeypatch):
monkeypatch.setattr(socket, 'gethostbyname', lambda hostname: "192.168.100.1")
result = resolve('test.local')
print(result)
assert (result == "192.168.100.1")
テストの実行は以下のようにします
pipenv run pytest
すると socket.gaierror: [Errno 8] nodename nor servname provided, or not known
というエラーが発生します
これは monkeypatch できずに実際に test.local
を DNS に問い合わせているために名前解決できずエラーになっています
なぜ monkeypatch できないのか
どうやらロジック側で import している方法とテスト側で import しているやり方を統一しないとダメなようです
今回だと from socket import gethostbyname
ではダメだということです
以下のようにロジック側を修正します
vim app.py
import socket
def resolve(hostname):
return socket.gethostbyname(hostname)
これで再度テストを実行すると正常に終了するのが確認できると思います
最後に
monkeypatch で組み込みモジュールをテストする場合はロジック側とテスト側の import 方法を合わせる必要があるということがわかりました
なかなか気づきにくい仕様かなと思います
しかし知らないとハマるので知っておいて損はないと思います
0 件のコメント:
コメントを投稿