pytest - monkeypatch 关键字参数默认
pytest - monkeypatch keyword argument default
我想测试一个函数的默认行为。我有以下内容:
# 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
。
为什么会这样?还有比显式传递默认值更好的解决方案吗?
这是因为当您导入 app 模块时,模块在导入时会被解释,所以一旦它被导入到 foo 中,模块看起来像这样:
# app/foo.py
DEFAULT_VALUE = 'hello'
def bar(text='hello'):
print(text)
当您调用函数时,函数内的代码会得到解释,这就解释了为什么您会看到猴子被修补了 DEFAULT_VALUE
函数默认值在函数定义时绑定。
当您在测试代码中时,定义该函数的模块已经被导入,通过在模块级常量上进行猴子修补来换掉默认值已经太晚了。该名称已被解析。
解决方法是像这样定义函数:
def bar(text=None):
if text is None:
text = DEFAULT_VALUE
print(text)
现在在函数 调用 时查找默认值,这意味着模块级别 default 上的 monkeypatch 仍然有效。
如果你不喜欢修改函数定义,那么你可以monkeypatch函数对象本身:
monkeypatch.setattr("app.foo.bar.__defaults__", ("test_hello",))
我想测试一个函数的默认行为。我有以下内容:
# 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
。
为什么会这样?还有比显式传递默认值更好的解决方案吗?
这是因为当您导入 app 模块时,模块在导入时会被解释,所以一旦它被导入到 foo 中,模块看起来像这样:
# app/foo.py
DEFAULT_VALUE = 'hello'
def bar(text='hello'):
print(text)
当您调用函数时,函数内的代码会得到解释,这就解释了为什么您会看到猴子被修补了 DEFAULT_VALUE
函数默认值在函数定义时绑定。
当您在测试代码中时,定义该函数的模块已经被导入,通过在模块级常量上进行猴子修补来换掉默认值已经太晚了。该名称已被解析。
解决方法是像这样定义函数:
def bar(text=None):
if text is None:
text = DEFAULT_VALUE
print(text)
现在在函数 调用 时查找默认值,这意味着模块级别 default 上的 monkeypatch 仍然有效。
如果你不喜欢修改函数定义,那么你可以monkeypatch函数对象本身:
monkeypatch.setattr("app.foo.bar.__defaults__", ("test_hello",))