2015-07-09 1 views
8

Предположим, что в проекте две упаковки: some_package и another_package.Pytest monkeypatch не работает на импортной функции

# some_package/foo.py: 
def bar(): 
    print('hello') 

# another_package/function.py 
from some_package.foo import bar 

def call_bar(): 
    # ... code ... 
    bar() 
    # ... code ... 

Я хочу проверить another_package.function.call_bar насмешливый из some_package.foo.bar, потому что он имеет некоторую сеть I/O, я хочу, чтобы избежать.

Вот тест:

# tests/test_bar.py 
from another_package.function import call_bar 

def test_bar(monkeypatch): 
    monkeypatch.setattr('some_package.foo.bar', lambda: print('patched')) 
    call_bar() 
    assert True 

К моему удивлению, он выводит hello вместо mock. Я попытался отладить эту вещь, поставив точку проверки ipdb в тесте. Когда я вручную импортирую some_package.foo.bar после точки останова и звоню bar(), я получаю patched.

В моем реальном проекте ситуация еще более интересная. Если я вызываю pytest в корне проекта, моя функция не исправлена, но когда я укажу tests/test_bar.py как аргумент - он работает.

Насколько я понимаю, это как-то связано с заявлением from some_package.foo import bar. Если он выполняется до того, как происходит monkeypatching, то исправление не выполняется. Но на сконденсированной тестовой установке из приведенного выше примера исправление не работает в обоих случаях.

И почему он работает в IPDB REPL после достижения точки останова?

ответ

6

назвал импорт создает новое имя для объекта, если вы замените старое имя объекта новое имя не влияет

импортировать модуль и использовать module.bar вместо, который всегда будет использовать текущий объект

редактировать:

import module 

def func_under_test(): 
    module.foo() 


def test_func(): 
    monkeypatch.setattr(...) 
    func_under_test 
+4

Это один из худших ошибок с помощью pytest - но, спасибо, что объяснил это. –

+0

Когда вы говорите «use module.bar», можете ли вы представить пример кода? Я пробовал 'monkeypatch.setattr (модуль, 'bar', mock_obj)' и несколько других заклинаний без успеха. – skolsuper

+0

Благодарим вас за ответ. Есть ли что-то трюк, чтобы быть уверенным, что любой импорт будет использовать насмешливый объект. Потому что пока это опасно, если, например, я пытаюсь высмеять orm-объект – Stavinsky

1

Хотя Ronny's answer работает он заставляет вас изменить код приложения. В общем, вы не должны делать этого ради тестирования.

Вместо этого вы можете явно исправить объект во втором пакете. Это упоминается в docs for the unittest module.

monkeypatch.setattr('another_package.bar', lambda: print('patched'))