【问题标题】:Pytest mock using decorator to mock function containing context manager return value not passedPytest 使用装饰器模拟包含未传递的上下文管理器返回值的函数
【发布时间】:2021-01-16 18:21:09
【问题描述】:

因此,由于上下文管理器,我正在努力模拟此功能。

被测函数

import fitz

def with_test_func(next_pdfs_path):
    text = ''
    with fitz.open(next_pdfs_path) as doc:
        text = doc
    return text

测试代码

@mock.patch("content_production.fitz.open.__enter__", return_value='value_out')
def test_with_test_func(mock_fitz_open):
    assert cp.with_test_func('value_in') == 'value_out'

错误

RuntimeError: cannot open value_in: No such file or directory

我已经在没有上下文管理器的情况下对此进行了测试,并且它可以工作。那么我将如何解决这个问题?谢谢

编辑

按照@MrBean 的建议,我尝试了这个

@mock.patch("content_production.fitz.open.return_value.__enter__", return_value='value_out')
def test_with_test_func(mock_fitz_open):
    assert cp.with_test_func('value_in') == 'value_out'

它给了我这个错误

thing = <class 'fitz.fitz.Document'>, comp = 'return_value', import_path = 'content_production.fitz.open.return_value'

    def _dot_lookup(thing, comp, import_path):
        try:
            return getattr(thing, comp)
        except AttributeError:
>           __import__(import_path)
E           ModuleNotFoundError: No module named 'content_production.fitz'; 'content_production' is not a package

【问题讨论】:

  • 我想你忘记了return_value,例如content_production.fitz.open.return_value.__enter__,获取open 调用的结果。
  • 谢谢我已经尝试过了,也喜欢这个content_production.fitz.open.__enter__.return_value,但它们不起作用。根据您的建议,错误是ModuleNotFoundError: No module named 'content_production.fitz'; 'content_production' is not a package
  • content_production 是你的功能在测试中的模块吗,它是*的吗?
  • 是顶层,是的,它是具有该功能的模块。就像我说它在没有上下文管理器的情况下工作一样,所以我认为上下文管理器的工作方式让我很受挫。
  • 抱歉,我的评论具有误导性 - 没有注意到明显的......我把它放在答案中。

标签: python-3.x unit-testing mocking pytest


【解决方案1】:

问题在于return_value 是模拟的属性,而不是修补函数的属性,因此您不能将其放入patch 参数字符串中。相反,您必须在模拟上为 open 方法设置返回值:

@mock.patch("content_production.fitz.open")
def test_with_test_func(mock_fitz_open):
    mock_fitz_open.return_value.__enter__.return_value = 'value_out'
    assert cp.with_test_func('value_in') == 'value_out'

【讨论】: