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

时间:2021-09-18 20:58:28

I've got a following structure:

我有一个以下结构:

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

bar.py

bar.py

def returnBar():
    return 'Bar'

foo.py

foo.py

from dirBar.bar import returnBar

def printFoo():
    print returnBar()

test.py

test.py

from mock import Mock

from foo import printFoo
from dirBar import bar

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

printFoo()

the result of python test.py is Bar.

python test.py的结果是Bar。

How to mock the printBar to make it return Foo so that printFoo will print it?

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

EDIT: Without modifying any other file that test.py

编辑:不修改任何其他test.py文件

4 个解决方案

#1


20  

I'm guessing you are going to mock the function returnBar, you'd like to use patch decorator:

我猜你要模拟函数returnBar,你想使用补丁装饰器:

from mock import patch

from foo import printFoo

@patch('foo.returnBar')
def test_printFoo(mockBar):
    mockBar.return_value = 'Foo'
    printFoo()

test_printFoo()

#2


24  

Just import the bar module before the foo module and mock it:

只需在foo模块之前导入bar模块并模拟它:

from mock import Mock

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

from foo import printFoo

printFoo()

When you are importing the returnBar in foo.py, you are binding the value of the module to a variable called returnBar. This variable is local so is put in the closure of the printFoo() function when foo is imported - and the values in the closure cannot be updated by code from outiside it. So, it should have the new value (that is, the mocking function) before the importing of foo.

在foo.py中导入returnBar时,将模块的值绑定到名为returnBar的变量。这个变量是本地的,因此在导入foo时放入printFoo()函数的闭包中 - 并且闭包中的值不能通过外部代码更新。因此,它应该在导入foo之前具有新值(即模拟函数)。

EDIT: the previous solution workis but is not robust since it depends on ordering the imports. That is not much ideal. Another solution (that occurred me after the first one) is to import the bar module in foo.py instead of only import the returnBar() function:

编辑:以前的解决方案工作但不健全,因为它取决于订购导入。那不太理想。另一个解决方案(在第一个解决方案之后发生)是在foo.py中导入bar模块而不是仅导入returnBar()函数:

from dirBar import bar

def printFoo():
    print bar.returnBar()

This will work because the returnBar() is now retrieved directly from the bar module instead of the closure. So if I update the module, the new function will be retrieved.

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

#3


4  

The best place I've found to solve mocking issues is: http://alexmarandon.com/articles/python_mock_gotchas/

我发现解决嘲弄问题的最佳地点是:http://alexmarandon.com/articles/python_mock_gotchas/

You should mock the function of the module being imported by the class under testing.

您应该模拟正在测试的类导入的模块的功能。

#4


-3  

Another way to deal with those case is to use some dependency injection.

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

An easy way to do it in python is to use the magical **kwargs :

在python中实现它的一个简单方法是使用神奇的** kwargs:

foo.py

foo.py

from dirBar.bar import returnBar

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

test.py

test.py

from mock import Mock

from foo import printFoo
from dirBar import bar

mocked_returnBar = Mock(return_value='Foo')

printFoo(returnBar=mocked_returnBar)

this will lead to a more testable code (and increase modularity/reusability).

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

#1


20  

I'm guessing you are going to mock the function returnBar, you'd like to use patch decorator:

我猜你要模拟函数returnBar,你想使用补丁装饰器:

from mock import patch

from foo import printFoo

@patch('foo.returnBar')
def test_printFoo(mockBar):
    mockBar.return_value = 'Foo'
    printFoo()

test_printFoo()

#2


24  

Just import the bar module before the foo module and mock it:

只需在foo模块之前导入bar模块并模拟它:

from mock import Mock

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

from foo import printFoo

printFoo()

When you are importing the returnBar in foo.py, you are binding the value of the module to a variable called returnBar. This variable is local so is put in the closure of the printFoo() function when foo is imported - and the values in the closure cannot be updated by code from outiside it. So, it should have the new value (that is, the mocking function) before the importing of foo.

在foo.py中导入returnBar时,将模块的值绑定到名为returnBar的变量。这个变量是本地的,因此在导入foo时放入printFoo()函数的闭包中 - 并且闭包中的值不能通过外部代码更新。因此,它应该在导入foo之前具有新值(即模拟函数)。

EDIT: the previous solution workis but is not robust since it depends on ordering the imports. That is not much ideal. Another solution (that occurred me after the first one) is to import the bar module in foo.py instead of only import the returnBar() function:

编辑:以前的解决方案工作但不健全,因为它取决于订购导入。那不太理想。另一个解决方案(在第一个解决方案之后发生)是在foo.py中导入bar模块而不是仅导入returnBar()函数:

from dirBar import bar

def printFoo():
    print bar.returnBar()

This will work because the returnBar() is now retrieved directly from the bar module instead of the closure. So if I update the module, the new function will be retrieved.

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

#3


4  

The best place I've found to solve mocking issues is: http://alexmarandon.com/articles/python_mock_gotchas/

我发现解决嘲弄问题的最佳地点是:http://alexmarandon.com/articles/python_mock_gotchas/

You should mock the function of the module being imported by the class under testing.

您应该模拟正在测试的类导入的模块的功能。

#4


-3  

Another way to deal with those case is to use some dependency injection.

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

An easy way to do it in python is to use the magical **kwargs :

在python中实现它的一个简单方法是使用神奇的** kwargs:

foo.py

foo.py

from dirBar.bar import returnBar

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

test.py

test.py

from mock import Mock

from foo import printFoo
from dirBar import bar

mocked_returnBar = Mock(return_value='Foo')

printFoo(returnBar=mocked_returnBar)

this will lead to a more testable code (and increase modularity/reusability).

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