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


125

我想了解如何@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"

测试/模拟测试.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。如何模拟要导入到被测名称空间中的其他包中的方法?


1
问题是关于“模拟最佳实践”,或者您在做什么是否有意义?关于第一个,我想说的是使用诸如Mock,在python3.3 +中包含的模拟库unittest.mock
Bakuriu

我问我是否要这样做。我看着Mock,但没有找到解决此特定问题的方法。有没有办法重现我在Mock中所做的事情?
nsfyn55

Answers:


167

当您patchunittest.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')

标准库文档中包含一个有用的部分对此进行了描述。


这解决了我的问题。get_user_name与的模块不同test_method。有没有办法在sub_module中模拟某些东西?我在下面以难看的方式修复了它。
nsfyn55

6
没关系get_user_name是在另一个模块中,而不是test_method因为将函数导入到app.mocking同一个命名空间中。
马蒂·约翰

2
test_patch来自哪里,究竟是什么?
Mike G

2
test_patch由修补程序装饰器传递,并且是模拟的get_user_name对象(即MagicMock类的实例)。如果将其命名为,可能会更清楚get_user_name_patch
马蒂·约翰

您如何引用test_method?这将导致错误,NameError:未定义全局名称“ test_method”
Aditya

12

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

6
这对提出的问题来说并不重要。无论您使用patch作为装饰或上下文管理是具体的使用情况。例如,您可以patch用作装饰器,以模拟xunitpytest类中所有测试的值,而在其他情况下,使用上下文管理器提供的细粒度控件非常有用。
nsfyn55
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.