Подтвердить что ты не робот

Как издеваться над функцией, определенной в модуле пакета?

У меня есть следующая структура:

|-- 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

4b9b3361

Ответ 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)

это приведет к более тестируемому коду (и увеличит модульность/возможность повторного использования).