Как издеваться над функцией, определенной в модуле пакета?
У меня есть следующая структура:
|-- dirBar
| |-- __init__.py
| |-- bar.py
|-- foo.py
`-- test.py
bar.py
def returnBar():
return 'Bar'
foo.py
from dirBar.bar import returnBar
def printFoo():
print returnBar()
test.py
from mock import Mock
from foo import printFoo
from dirBar import bar
bar.returnBar = Mock(return_value='Foo')
printFoo()
результат python test.py
равен Bar
.
Как издеваться над printBar
, чтобы вернуть его Foo
, чтобы printFoo
напечатал его?
EDIT: без изменения любого другого файла, который test.py
Ответы
Ответ 1
Просто импортируйте модуль bar
перед модулем foo
и издевайтесь над ним:
from mock import Mock
from dirBar import bar
bar.returnBar = Mock(return_value='Foo')
from foo import printFoo
printFoo()
Когда вы импортируете returnBar
в foo.py
, вы привязываете значение модуля к переменной с именем returnBar
. Эта переменная является локальной, поэтому помещается в закрытие функции printFoo()
, когда foo
импортируется - и значения в закрытии не могут быть обновлены кодом из outseide it. Таким образом, перед импортом foo
он должен иметь новое значение (то есть функцию насмешивания).
EDIT: предыдущее решение работает, но не является надежным, поскольку оно зависит от порядка импорта. Это не очень хорошо. Еще одно решение (которое произошло после первого) - импортировать модуль bar
в foo.py
вместо импорта функции returnBar()
:
from dirBar import bar
def printFoo():
print bar.returnBar()
Это будет работать, потому что returnBar()
теперь извлекается непосредственно из модуля bar
вместо закрытия. Поэтому, если я обновляю модуль, будет восстановлена новая функция.
Ответ 2
Я предполагаю, что вы собираетесь издеваться над функцией returnBar
, вы хотели бы использовать patch
decorator:
from mock import patch
from foo import printFoo
@patch('foo.returnBar')
def test_printFoo(mockBar):
mockBar.return_value = 'Foo'
printFoo()
test_printFoo()
Ответ 3
Лучшее место, которое я нашел для решения насмешек, это: http://alexmarandon.com/articles/python_mock_gotchas/
Вы должны высмеять функцию модуля, импортируемого тестируемым классом.
Ответ 4
Другой способ справиться с этим случаем - использовать некоторую инъекцию зависимости.
Простым способом сделать это в python является использование магического **kwargs
:
foo.py
from dirBar.bar import returnBar
def printFoo(**kwargs):
real_returnBar = kwargs.get("returnBar", returnBar)
print real_returnBar()
test.py
from mock import Mock
from foo import printFoo
from dirBar import bar
mocked_returnBar = Mock(return_value='Foo')
printFoo(returnBar=mocked_returnBar)
это приведет к более тестируемому коду (и увеличит модульность/возможность повторного использования).