Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用pythonmock模拟函数_Python_Unit Testing_Mocking - Fatal编程技术网

使用pythonmock模拟函数

使用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方面,我遗

我正在尝试使用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.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
s
util.get\u content()
,而不仅仅是调用它。我觉得你的描述中肯定还缺少一些信息。你真的试过上面的描述吗?你的实际代码是什么?很抱歉-我避免了粘贴大量代码。你是对的-我的简化示例并没有完全失败,但我认为我已经部分地找到了解决方案。奇怪的是,在我更复杂的Django测试用例中,事情并没有正常工作,但是当我尝试提取它时,模拟对象似乎像预期的那样被传递。我猜在导入中会有一些不同,这会创建稍微不同的名称空间。我非常喜欢一般情况下的答案。有时,util import get_context的
语法可用于模拟,有时则不能。有人解释吗?非常感谢你的回答。我很困惑,为什么我的mock在某些文件中有效,而在其他文件中无效。@johnboiles回答“为什么它有时有效,有时无效”:导入顺序在这里很重要。如果在导入之前执行mock,那么导入就不起作用了。如果我们想模拟一个内置函数,比如
open
,该怎么办?