我有以下结构:
|-- dirBar
| |-- __init__.py
| |-- bar.py
|-- foo.py
`-- test.py
bar.py
def returnBar():
return 'Bar'
foo.py
from dirBar.bar import returnBar
def printFoo():
print returnBar()
test.py
from mock import Mock
from foo import printFoo
from dirBar import bar
bar.returnBar = Mock(return_value='Foo')
printFoo()
python test.py
的结果是Bar
。
如何模仿printBar
以使其返回Foo
以便printFoo
将其打印出来?
编辑:不修改test.py
答案 0 :(得分:32)
我猜你要嘲笑函数returnBar
,你想使用patch
decorator:
from mock import patch
from foo import printFoo
@patch('foo.returnBar')
def test_printFoo(mockBar):
mockBar.return_value = 'Foo'
printFoo()
test_printFoo()
答案 1 :(得分:25)
只需在bar
模块之前导入foo
模块并模拟它:
from mock import Mock
from dirBar import bar
bar.returnBar = Mock(return_value='Foo')
from foo import printFoo
printFoo()
在returnBar
中导入foo.py
时,您将模块的值绑定到名为returnBar
的变量。这个变量是局部的,因此在导入printFoo()
时放入foo
函数的闭包中 - 并且闭包中的值不能通过代码来更新。因此,在导入foo
之前,它应该具有新值(即模拟函数)。
编辑:之前的解决方案有效,但不健全,因为它取决于订购导入。那不太理想。另一个解决方案(在第一个解决方案之后发生)是导入bar
中的foo.py
模块,而不是仅导入returnBar()
函数:
from dirBar import bar
def printFoo():
print bar.returnBar()
这将起作用,因为returnBar()
现在直接从bar
模块而不是闭包中检索。因此,如果我更新模块,将检索新函数。
答案 2 :(得分:-3)
处理这些情况的另一种方法是使用一些依赖注入。
在python中执行此操作的一种简单方法是使用神奇的**kwargs
:
foo.py
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
mocked_returnBar = Mock(return_value='Foo')
printFoo(returnBar=mocked_returnBar)
这将导致更可测试的代码(并增加模块化/可重用性)。