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)
pypython 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就是这样。。我想知道为什么我的模拟不起作用。这里的小费真是太好了