pytest — аргумент ключевого слова monkeypatch по умолчанию

Я хотел бы проверить поведение функции по умолчанию. У меня есть следующее:

# app/foo.py
DEFAULT_VALUE = 'hello'

def bar(text=DEFAULT_VALUE):
    print(text)
# test/test_app.py
import app

def test_app(monkeypatch):
    monkeypatch.setattr('app.foo.DEFAULT_VALUE', 'patched')
    app.foo.bar()
    assert 0

Выход hello; не то, что я хотел.

Одним из решений является явная передача значения по умолчанию: app.foo.bar(text=app.foo.DEFAULT_VALUE).

Но мне интересно, что это не кажется проблемой при использовании по умолчанию глобальной области видимости:

# app/foo.py
DEFAULT_VALUE = 'hello'

def bar():
    print(DEFAULT_VALUE)

Выход patched.

Почему это происходит? И есть ли лучшее решение, чем явно передать значение по умолчанию?


person Nathaniel Jones    schedule 17.12.2018    source источник
comment
Возможный дубликат Как исправить константу в python   -  person Michael H.    schedule 17.12.2018


Ответы (2)


Значения функций по умолчанию привязаны к времени определения функции.

К тому времени, когда вы находитесь в тестовом коде, модуль, в котором была определена функция, уже был импортирован, и уже слишком поздно менять значение по умолчанию путем внесения обезьяньих исправлений в константу уровня модуля. Это имя уже было разрешено.

Обходной путь состоит в том, чтобы определить функцию следующим образом:

def bar(text=None):
    if text is None:
        text = DEFAULT_VALUE
    print(text)

Теперь значение по умолчанию просматривается во время вызова функции, что означает, что обезьяний патч на уровне модуля по умолчанию будет работать.

Если вам не нравится изменять определение функции, вы можете изменить сам объект функции:

monkeypatch.setattr("app.foo.bar.__defaults__", ("test_hello",))
person wim    schedule 24.09.2019

Это связано с тем, что когда вы импортируете модуль приложения, модуль интерпретируется при импорте, поэтому после импорта в foo модуль выглядит следующим образом:

# app/foo.py
DEFAULT_VALUE = 'hello'

def bar(text='hello'):
    print(text)

Когда вы вызываете функцию, код внутри функции интерпретируется, что объясняет, почему вы видите, что обезьяна исправлена ​​DEFAULT_VALUE

person Paul Novacovici    schedule 24.09.2019