【问题标题】:Python Mocking a function from an imported modulePython 从导入的模块中模拟一个函数
【发布时间】:2013-04-14 14:20:41
【问题描述】:

我想了解如何@patch 导入模块中的函数。

这是我目前为止的地方。

app/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()

app/my_module/__init__.py:

def get_user_name():
  return "Unmocked User"

test/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()

这确实按我的预期工作。 “已修补”模块仅返回 get_user_name 的未模拟值。如何模拟我要导入到正在测试的命名空间的其他包中的方法?

【问题讨论】:

  • 我在问我是否要这样做。我查看了 Mock,但我没有看到解决这个特定问题的方法。有没有办法重新创建我在 Mock 中所做的事情?

标签: python unit-testing python-unittest python-mock


【解决方案1】:

当您使用 unittest.mock 包中的 patch 装饰器时,您在被测试的命名空间中修补它(在本例中为 app.mocking.get_user_name),而不是函数的命名空间从(在本例中为 app.my_module.get_user_name)导入。

要按照@patch 的描述执行操作,请尝试以下操作:

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

标准库文档包含一个有用的section 对此进行描述。

【讨论】:

  • 这就是我的问题。 get_user_nametest_method 位于不同的模块中。有没有办法在 sub_module 中模拟某些东西?我在下面用丑陋的方式修复了它。
  • get_user_nametest_method 位于不同的模块中并不重要,因为您将函数导入到 app.mocking 中,它们位于同一个命名空间中。
  • test_patch 是从哪里来的,到底是什么?
  • test_patch 由补丁装饰器传入,是模拟的 get_user_name 对象(即 MagicMock 类的实例)。如果将其命名为get_user_name_patch 之类的名称可能会更清楚。
  • 你是如何引用 test_method 的?会报错,NameError: global name 'test_method' is not defined
【解决方案2】:

虽然 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')

【讨论】:

  • 这对于提出的问题来说是无关紧要的。无论您使用 patch 作为装饰器还是上下文管理器,都特定于用例。例如,您可以使用 patch 作为装饰器来模拟 xunitpytest 类中所有测试的值,而在其他情况下,它对上下文管理器提供的细粒度控制很有用。
猜你喜欢
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
  • 2011-10-09
  • 2022-11-11
  • 2020-12-09
相关资源
最近更新 更多