Два местоположения foo.requests.get
и bar.requests.get
относятся к одному и тому же объекту, поэтому издевайтесь над ним в одном месте, и вы издеваетесь над ним в другом месте.
Представьте, как вы можете использовать патч. Вы должны найти, где находится символ, и заменить символ макетным объектом. При выходе из контекста вам нужно будет восстановить исходное значение символа. Что-то вроде (непроверенные):
class patch(object):
def __init__(self, symbol):
# separate path to container from name being mocked
parts = symbol.split('.')
self.path = '.'.join(parts[:-1]
self.name = parts[-1]
def __enter__(self):
self.container = ... lookup object referred to by self.path ...
self.save = getattr(self.container, name)
setattr(self.container, name, MagicMock())
def __exit__(self):
setattr(self.container, name, self.save)
Так что ваша проблема заключается в том, что вы насмешливый объект в модуле запроса, который затем имеют в виду как из Foo и бар.
По предложению @ elethan, вы могли издеваться модуль запросов в обув, и даже обеспечить побочные эффекты на методе ПОЛУЧАЕТЕ:
from unittest import mock
import requests
from foo import get_ip
from bar import get_fb
def fake_get(*args, **kw):
print("calling get with", args, kw)
return mock.DEFAULT
replacement = mock.MagicMock(requests)
replacement.get = mock.Mock(requests.get, side_effect=fake_get, wraps=requests.get)
with mock.patch('foo.requests', new=replacement):
print(get_ip())
print(get_fb())
Более прямое решение заключается в изменении кода так что foo
и bar
вытащите ссылку на get
прямо на свое пространство имен.
foo.py:
from requests import get
def get_ip():
return get('http://jsonip.com/').content
bar.py:
from requests import get
def get_ip():
return get('https://fb.com/').content
main.py:
from mock import patch
from foo import get_ip
from bar import get_fb
with patch('foo.get'):
print(get_ip())
print(get_fb())
производство:
<MagicMock name='get().content' id='4350500992'>
b'<!DOCTYPE html>\n<html lang="en" id="facebook" ...
обновление с более полным объяснением, и с лучшим решением (2016-10-15)
Примечания: добавлен wraps=requests.get
для вызова основной функции после побочного эффекта.
Я думаю, с помощью декоратора пропатчить функции следует сделать трюк. – Dan