Python 如何模拟在包的模块中定义的函数?

Python 如何模拟在包的模块中定义的函数?,python,mocking,Python,Mocking,我有以下结构: |-- dirBar | |-- __init__.py | |-- bar.py |-- foo.py `-- test.py 巴比 def returnBar(): return 'Bar' 福比 from dirBar.bar import returnBar def printFoo(): print returnBar() from dirBar.bar import returnBar def printFoo(**kwargs):

我有以下结构:

|-- dirBar
|   |-- __init__.py
|   |-- bar.py
|-- foo.py
`-- test.py
巴比

def returnBar():
    return 'Bar'
福比

from dirBar.bar import returnBar

def printFoo():
    print returnBar()
from dirBar.bar import returnBar

def printFoo(**kwargs):
    real_returnBar = kwargs.get("returnBar", returnBar)
    print real_returnBar()
test.py

from mock import Mock

from foo import printFoo
from dirBar import bar

bar.returnBar = Mock(return_value='Foo')

printFoo()
from mock import Mock

from foo import printFoo
from dirBar import bar

mocked_returnBar = Mock(return_value='Foo')

printFoo(returnBar=mocked_returnBar)
py
python test.py
的结果是
Bar

如何模拟
printBar
使其返回
Foo
,以便
printFoo
将其打印出来


编辑:不修改
test.py
的任何其他文件,只需在
foo
模块之前导入
bar
模块并模拟它:

from mock import Mock

from dirBar import bar
bar.returnBar = Mock(return_value='Foo')

from foo import printFoo

printFoo()
foo.py
中导入
returnBar
时,您将模块的值绑定到名为
returnBar
的变量。此变量是本地变量,因此在导入
foo
时,会将其放入
printFoo()
函数的闭包中,并且闭包中的值不能由outiside中的代码更新。因此,在导入
foo
之前,它应该具有新的值(即mocking函数)

编辑:以前的解决方案工作正常,但不稳定,因为它取决于导入的顺序。这并不太理想。另一个解决方案(在第一个解决方案之后出现)是在
foo.py
中导入
bar
模块,而不是只导入
returnBar()
函数:

from dirBar import bar

def printFoo():
    print bar.returnBar()

这将起作用,因为
returnBar()
现在直接从
bar
模块而不是闭包中检索。因此,如果我更新模块,将检索新函数。

我猜您将模拟函数
returnBar
,您希望使用:


处理这种情况的另一种方法是使用依赖注入

在python中,一个简单的方法是使用神奇的
**kwargs

福比

from dirBar.bar import returnBar

def printFoo():
    print returnBar()
from dirBar.bar import returnBar

def printFoo(**kwargs):
    real_returnBar = kwargs.get("returnBar", returnBar)
    print real_returnBar()
test.py

from mock import Mock

from foo import printFoo
from dirBar import bar

bar.returnBar = Mock(return_value='Foo')

printFoo()
from mock import Mock

from foo import printFoo
from dirBar import bar

mocked_returnBar = Mock(return_value='Foo')

printFoo(returnBar=mocked_returnBar)

这将导致更可测试的代码(并增加模块化/可重用性)。

整个想法是除了测试之外不修改任何东西。是的,问题是-我有这样的代码,我不想更改它们。在讨论了freenode#python之后,我决定重构另一个文件(这里是foo.py),这样它会更好、更安全cleaner@zalun是否有与此讨论的链接?我对此很好奇!令人惊讶的是,我自己听从我的建议,创建了一个ctx管理器/装饰器来模拟模块中的属性,这让我有点恼火:也许它对某些人有用,或者可以作为参考。也就是说,避免依赖仍然是一个好主意;我这么做是因为我对很多项目都有依赖性!缺少的一点是,您在函数导入的位置修补函数,而不是在函数导入的位置修补函数。在
foo.py
中以
的形式从dirBar.bar导入returnBar
后,模拟需要将导入修补为
foo.returnBar
,而不是
dirBar.bar.returnBar
@hughdbrown
基本原则是修补查找对象的位置,它不一定与定义它的位置相同。几个例子将有助于澄清这一点。
@hughdbrown就是这样。。我想知道为什么我的模拟不起作用。这里的小费真是太好了