【问题标题】:How can I mock a module that is imported from a function and not present in sys.path? [duplicate]如何模拟从函数导入但不存在于 sys.path 中的模块? [复制]
【发布时间】:2017-06-11 22:50:41
【问题描述】:

我是unittesting 代码,其中包含一个执行本地导入的方法。

def function_under_test():
    import unknown.dependency

(我没有在 .py 文件的顶部使用导入,因为在调用函数时它可能存在也可能不存在。)

只有在sys.path 的某处可以找到它时,才能以通常的方式模拟unknown.dependency。否则,对patch 的调用会失败(它拒绝模拟它看不到的东西):

with mock.patch('unknown.dependency'):
    function_under_test()
>>> ImportError: No module named 'unknown'

文档建议我应该修补到使用模块的命名空间——在这种情况下,function_under_test。但是,当该命名空间是一个函数时,这并没有削减它。对patch 的调用成功,但实际的导入语句仍在引用原始的、不存在的unknown 模块,无法找到。

with mock.patch('method_under_test.unknown'):
    print("fails")
>>> ImportError: No module named 'unknown'

那么,如果模块本身不存在并且它是从函数中导入的,我该如何用mock替换依赖模块?

【问题讨论】:

  • 这里的目标是什么?要在缺少依赖项时跳过测试,或者模拟 if 依赖项丢失,被测代码以特定方式处理吗?
  • 对于导入语句,可接受的方法是修补sys.modulesimport 语句中没有对象,只有名称,所以没有对象to 补丁。
  • 目标是测试被测代码,就像依赖存在一样,但实际上并不存在。
  • 所以你想模拟整个模块?那么这是对您链接的帖子的欺骗;你会模拟 sys.modules 来插入一个模拟对象来替换依赖项。
  • 我现在明白为什么它是骗子了。导入语句是在文件顶部还是在函数中无关紧要——问题是模块不存在,我仍然想模拟它。

标签: python mocking python-unittest


【解决方案1】:

仅模拟导入

简单的方法是将 import 语句移到一个单独的函数中。

def get_dependency():
    import unknown.dependency
    return unknown.dependency

def function_under_test():
    module = get_dependency()
    # use module

这使得只模拟那个“帮助”函数变得很容易。这样做的缺点是需要更改被测代码。但它确实有效:

with mock.patch('get_dependency'):
    function_under_test()

模拟模块

here 所述,您可以将模拟模块直接添加到sys.modules,以便Python 可以找到它,无论它是否存在于sys.path 中。

with mock.patch.dict('sys.modules', unknown=mock.MagicMock()):
    function_under_test()

【讨论】:

  • 什么是unknown?它代表什么,它是强制性的吗?背后的含义是什么?
  • @kev 这是一个 Python 模块,在测试时可能不存在。
  • 发现它对于模拟 plpy 非常有用,这仅在带有 plpythonu 扩展的 postgres 中可用。
猜你喜欢
  • 1970-01-01
  • 2018-03-28
  • 2022-12-07
  • 2013-04-14
  • 1970-01-01
  • 2017-02-06
  • 2016-03-16
相关资源
最近更新 更多