Python从导入的模块中模拟一个函数

nsf*_*n55 95 python unit-testing python-mock python-unittest

我想了解如何@patch从导入的模块中获取函数.

这是我到目前为止的地方.

应用程序/ mocking.py:

from app.my_module import get_user_name

def test_method():
  return get_user_name()

if __name__ == "__main__":
  print "Starting Program..."
  test_method()
Run Code Online (Sandbox Code Playgroud)

应用程序/ my_module/__ init__.py:

def get_user_name():
  return "Unmocked User"
Run Code Online (Sandbox Code Playgroud)

测试/ mock-test.py:

import unittest
from app.mocking import test_method 

def mock_get_user():
  return "Mocked This Silly"

@patch('app.my_module.get_user_name')
class MockingTestTestCase(unittest.TestCase):

  def test_mock_stubs(self, mock_method):
    mock_method.return_value = 'Mocked This Silly')
    ret = test_method()
    self.assertEqual(ret, 'Mocked This Silly')

if __name__ == '__main__':
  unittest.main()
Run Code Online (Sandbox Code Playgroud)

这并没有工作,我期望的那样."patched"模块只返回unmocked值get_user_name.如何从我导入到测试命名空间的其他包中模拟方法?

Mat*_*ohn 131

当您使用包中的patch装饰器时,unittest.mock没有修补从中导入模块的命名空间(在本例中app.my_module.get_user_name),您正在测试的命名空间中修补它app.mocking.get_user_name.

Mock尝试上面的尝试,如下所示:

from mock import patch
from app.mocking import test_method 

class MockingTestTestCase(unittest.TestCase):

    @patch('app.mocking.get_user_name')
    def test_mock_stubs(self, test_patch):
        test_patch.return_value = 'Mocked This Silly'
        ret = test_method()
        self.assertEqual(ret, 'Mocked This Silly')
Run Code Online (Sandbox Code Playgroud)

标准库文档包含一个描述这一点的有用部分.

  • `get_user_name`与`test_method`位于不同的模块中并不重要,因为您将函数导入`app.mocking`它们位于同一名称空间中. (6认同)
  • 这就是我的问题。`get_user_name` 与 `test_method` 位于不同的模块中。有没有办法模拟子模块中的某些内容?我在下面以一种丑陋的方式修复了它。 (2认同)
  • test_patch来自哪里,究竟是什么? (2认同)
  • test_patch由补丁装饰器传入,并且是模拟的get_user_name对象(即MagicMock类的实例)。如果它被命名为“ get_user_name_patch”之类的名称,可能会更清楚。 (2认同)
  • 我刚才遇到的一个小警告是“来自模拟导入补丁”行*必须*是第一行。如果先导入test_method,再导入patch,是不行的。只是想强调这一点。 (2认同)

Tgi*_*gul 8

虽然Matti John的答案解决了你的问题(也帮助了我,谢谢!),但是,我建议将原始的'get_user_name'函数替换为模拟的函数.这将允许您控制何时更换功能以及何时更换功能.此外,这将允许您在同一测试中进行多次替换.为此,请以非常类似的方式使用"with"语句:

from mock import patch

class MockingTestTestCase(unittest.TestCase):

    def test_mock_stubs(self):
        with patch('app.mocking.get_user_name', return_value = 'Mocked This Silly'):
            ret = test_method()
            self.assertEqual(ret, 'Mocked This Silly')
Run Code Online (Sandbox Code Playgroud)

  • 这对提出的问题来说无关紧要.是否使用`patch`作为装饰器或上下文管理器是特定于用例的.例如,您可以使用`patch`作为装饰器来模拟`xunit`或`pytest`类中所有测试的值,而在其他情况下,它可用于上下文管理器提供的细粒度控制. (5认同)