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

时间:2011-12-20 12:50:10

标签: python mocking

我有以下结构:

|-- 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

的任何其他文件

3 个答案:

答案 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)

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