pytest-默认的Monkeypatch关键字参数

时间:2018-12-17 19:51:07

标签: python pytest monkeypatching

我想测试一个函数的默认行为。我有以下内容:

# 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

为什么会这样?还有比明确传递默认值更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

默认功能在函数定义时间绑定。

在您进入测试代码之时,定义功能的模块已经导入,现在通过在模块级别常量上进行monkeypatching换出默认值已经太迟了。这个名字已经解决了。

一种解决方法是定义如下函数:

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

现在,默认值是在函数 call 时查找的,这意味着在模块级别default上的Monkeypatch仍然可以工作。

如果您不想修改函数定义,则可以对函数对象本身进行猴子修补:

monkeypatch.setattr("app.foo.bar.__defaults__", ("test_hello",))

答案 1 :(得分:0)

这是因为,当您导入应用程序模块时,模块在导入时会得到解释,因此一旦将其导入到foo中,模块将如下所示:

# app/foo.py
DEFAULT_VALUE = 'hello'

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

调用函数时,将解释函数内部的代码,这解释了为什么您看到猴子修补了DEFAULT_VALUE