Pytest monkeypatch不适用于导入的函数
问题描述
假设项目中有两个包:some_package
和another_package
。
# 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
而不是patched
。我试图调试这个东西,在测试中设置了IPDB断点。当我在断点后手动导入some_package.foo.bar
并调用bar()
时,我得到patched
。
在我的实际项目中,情况更加有趣。如果我在项目根目录中调用pytest,我的函数不会打补丁,但是当我指定tests/test_bar.py
作为参数时-它可以工作。
据我了解,它与from some_package.foo import bar
语句有关。如果它是在monkeypatching发生之前执行的,则修补失败。但是,在上面示例中的精简测试设置上,打补丁不能在两种情况下都起作用。
为什么它在命中断点后在IPDB REPL中工作?
解决方案
命名导入为对象创建新名称。如果然后替换对象的旧名称,则新名称不受影响。
导入模块并改用module.bar
。它将始终使用当前对象。
编辑:
import module
def func_under_test():
module.foo()
def test_func():
monkeypatch.setattr(...)
func_under_test
相关文章