如何模拟在 python 中为特定路径打开的文件?

Jed*_*sey 3 python unit-testing mocking python-unittest

所以我知道在我的单元测试中我可以模拟上下文管理器 open(),即:

with open('file_path', 'r') as stats:
Run Code Online (Sandbox Code Playgroud)

嘲笑与

with mock.patch('builtins.open', mock.mock_open(read_data=mock_json)):
Run Code Online (Sandbox Code Playgroud)

但有没有办法让我只模拟特定的文件路径?或者也许有其他方法来确保在单元测试中使用正确的路径调用上下文管理器?

MrB*_*men 7

open仅模拟特定路径,您必须提供自己的模拟对象,该对象open根据路径进行不同的处理。假设我们有一些功能:

def do_open(path):
    with open(path, "r") as f:
        return f.read()
Run Code Online (Sandbox Code Playgroud)

如果是“foo”,则应open模拟其中返回内容为“bar”的文件path,但否则就照常工作,您可以执行以下操作:

from unittest import mock
from my_module.do_open import do_open

builtin_open = open  # save the unpatched version

def mock_open(*args, **kwargs):
    if args[0] == "foo":
        # mocked open for path "foo"
        return mock.mock_open(read_data="bar")(*args, **kwargs)
    # unpatched version for every other path
    return builtin_open(*args, **kwargs)

@mock.patch("builtins.open", mock_open)
def test_open():
    assert do_open("foo") == "bar"
    assert do_open(__file__) != "bar"
Run Code Online (Sandbox Code Playgroud)

如果您不想将原始数据保存open在全局变量中,您也可以将其包装到一个类中:

class MockOpen:
    builtin_open = open

    def open(self, *args, **kwargs):
        if args[0] == "foo":
            return mock.mock_open(read_data="bar")(*args, **kwargs)
        return self.builtin_open(*args, **kwargs)

@mock.patch("builtins.open", MockOpen().open)
def test_open():
    ...
Run Code Online (Sandbox Code Playgroud)