使用pythonmock模拟函数
我正在尝试使用python模拟一个函数(返回一些外部内容) 我在模拟导入到模块中的函数时遇到一些问题 例如,在使用pythonmock模拟函数,python,unit-testing,mocking,Python,Unit Testing,Mocking,我正在尝试使用python模拟一个函数(返回一些外部内容) 我在模拟导入到模块中的函数时遇到一些问题 例如,在util.py中 def get_content(): return "stuff" 我想模拟util.get\u content,以便它返回其他内容 我正在尝试: util.get_content=Mock(return_value="mocked stuff") 如果在另一个模块中调用了get\u content,它实际上似乎永远不会返回模拟对象。在如何使用Mock方面,我遗
util.py
中
def get_content():
return "stuff"
我想模拟util.get\u content
,以便它返回其他内容
我正在尝试:
util.get_content=Mock(return_value="mocked stuff")
如果在另一个模块中调用了get\u content
,它实际上似乎永远不会返回模拟对象。在如何使用Mock
方面,我遗漏了什么吗
请注意,如果我调用以下命令,事情就会正常工作:
>>> util.get_content=Mock(return_value="mocked stuff")
>>> util.get_content()
"mocked stuff"
但是,如果从另一个模块内部调用get\u content
,它将调用原始函数,而不是模拟版本:
>>> from mymodule import MyObj
>>> util.get_content=Mock(return_value="mocked stuff")
>>> m=MyObj()
>>> m.func()
"stuff"
mymodule.py的内容
from util import get_content
class MyObj:
def func():
get_content()
所以我想我的问题是-如何从我调用的模块中调用模拟版本的函数
这里似乎应该归咎于模块导入函数的,因为它没有指向模拟函数。假设您正在模块内部创建模拟foobar
:
import util, mock
util.get_content = mock.Mock(return_value="mocked stuff")
如果导入mymodule
并调用util.get\u content
而不首先导入foobar
,则不会安装您的mock:
import util
def func()
print util.get_content()
func()
"stuff"
相反:
import util
import foobar # substitutes the mock
def func():
print util.get_content()
func()
"mocked stuff"
请注意,只要在调用util.get\u content
之前对foobar
进行评估,就可以从任何地方导入foobar
。我想我有一个解决方法,尽管对于如何解决一般情况还不太清楚
在mymodule
中,如果我更换
from util import get_content
class MyObj:
def func():
get_content()
与
Mock
似乎被调用。看起来名称空间需要匹配(这很有意义)。然而,奇怪的是,我希望
import mymodule
mymodule.get_content = mock.Mock(return_value="mocked stuff")
在我使用from/import语法(现在将get_content
拉入mymodule
)的原始情况下执行此技巧。但这仍然是指未修改的get\u内容
名称空间很重要-在编写代码时只需记住这一点。您必须在使用它的地方修补函数。在您的情况下,这将在mymodule中
import mymodule
>>> mymodule.get_content = Mock(return_value="mocked stuff")
>>> m = mymodule.MyObj()
>>> m.func()
"mocked stuff"
这里的文档中有一个参考:虽然它不能直接回答您的问题,但另一个可能的替代方法是使用@staticmethod将您的函数转换为静态方法
因此,您可以使用以下方法将模块UTIL转换为类:
class util(object):
@staticmethod
def get_content():
return "stuff"
然后mock正确地对其进行修补。一般情况是使用mock
中的patch
。考虑以下事项:
utils.py
def get_content():
return 'stuff'
from util import get_content
class MyClass(object):
def func(self):
return get_content()
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
@patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
mymodule.py
def get_content():
return 'stuff'
from util import get_content
class MyClass(object):
def func(self):
return get_content()
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
@patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
test.py
def get_content():
return 'stuff'
from util import get_content
class MyClass(object):
def func(self):
return get_content()
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
@patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
注意get\u content
是如何被模拟的,它不是util.get\u content
,而是mymodule.get\u content
,因为我们在mymodule
中使用它
上面已经用mock v2.0.0、nosetests v1.3.7和python v2.7.9进行了测试。我遵循了您的确切描述(在python 2.5中,在linux上使用mock 0.7.0),它工作得很好。你还有什么可以提供的详细信息吗?嗯,当从顶级作用域调用函数时,它的行为似乎与预期的一样。然而,当它从另一个模块或函数内部被调用时(即调用堆栈的下一层),它不会表现出模仿的行为。我正在澄清这个例子来说明这一点。好的,我尝试了你的新描述-我仍然得到了正确的答案,即使是从mymodule.func()
。对我来说唯一的区别是我的mymodule.func()
return
sutil.get\u content()
,而不仅仅是调用它。我觉得你的描述中肯定还缺少一些信息。你真的试过上面的描述吗?你的实际代码是什么?很抱歉-我避免了粘贴大量代码。你是对的-我的简化示例并没有完全失败,但我认为我已经部分地找到了解决方案。奇怪的是,在我更复杂的Django测试用例中,事情并没有正常工作,但是当我尝试提取它时,模拟对象似乎像预期的那样被传递。我猜在导入中会有一些不同,这会创建稍微不同的名称空间。我非常喜欢一般情况下的答案。有时,util import get_context的语法可用于模拟,有时则不能。有人解释吗?非常感谢你的回答。我很困惑,为什么我的mock在某些文件中有效,而在其他文件中无效。@johnboiles回答“为什么它有时有效,有时无效”:导入顺序在这里很重要。如果在导入之前执行mock,那么导入就不起作用了。如果我们想模拟一个内置函数,比如open
,该怎么办?