问题 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 代替 mock。我试着在测试中调试ipdb断点这个东西。我手动导入时 some_package.foo.bar 在断点和通话之后 bar() 我明白了 patched

在我的真实项目中,情况更加有趣。如果我在项目根目录中调用pytest,我的函数不会被修补,但是当我指定时 tests/test_bar.py 作为一个论点 - 它的作用。

据我所知,它与the有关 from some_package.foo import bar 声明。如果在monkeypatching发生之前执行它,那么它的修补失败。但是在上面示例的精简测试设置中,修补在两种情况下都不起作用。

为什么在遇到断点后它在IPDB REPL中工作?


6389
2017-07-09 00:18


起源



答案:


命名导入为对象创建新名称,如果然后替换对象的旧名称,则新名称不受影响

导入模块并使用module.bar,它将始终使用当前对象

编辑:

import module 

def func_under_test():
  module.foo()


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

6
2017-07-31 12:46



这是pytest最糟糕的陷阱之一 - 但感谢您的解释。 - Brighid McDonnell
当你说“使用module.bar”时,你能提供代码示例吗?我努力了 monkeypatch.setattr(module, 'bar', mock_obj) 和其他一些咒语没有成功。 - skolsuper
谢谢您的回答。是否有一些技巧可以确保任何导入都将使用模拟对象。因为现在如果我试图模仿orm对象是危险的 - Stavinsky
这是python语言的属性,没有技巧 - Ronny


答案:


命名导入为对象创建新名称,如果然后替换对象的旧名称,则新名称不受影响

导入模块并使用module.bar,它将始终使用当前对象

编辑:

import module 

def func_under_test():
  module.foo()


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

6
2017-07-31 12:46



这是pytest最糟糕的陷阱之一 - 但感谢您的解释。 - Brighid McDonnell
当你说“使用module.bar”时,你能提供代码示例吗?我努力了 monkeypatch.setattr(module, 'bar', mock_obj) 和其他一些咒语没有成功。 - skolsuper
谢谢您的回答。是否有一些技巧可以确保任何导入都将使用模拟对象。因为现在如果我试图模仿orm对象是危险的 - Stavinsky
这是python语言的属性,没有技巧 - Ronny


罗尼的回答 它会迫使您更改应用程序代码。一般来说,为了测试,你不应该这样做。

相反,您可以在第二个包中明确修补该对象。这是在提到的 单元测试模块的文档

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

7
2017-08-02 16:59



这显然是一种简单的monkeypatching导入方式。 - Floran Gmehlin