gpt4 book ai didi

python - pytest-mock pathlib.Path.open

转载 作者:行者123 更新时间:2023-12-04 16:45:49 25 4
gpt4 key购买 nike

我需要模拟 pathlib.Path.open使用 pytest-mock .

真实open_func打开一个 yaml-file .返回值是一个正则 dict .我如何模拟 Path.open只需加载另一个 yaml-filetest-config.yaml ?

我的代码无法正常工作,因为 conf将简单地变成 str (“test_config.yaml”)。应该是 dict .

from pathlib import Path

import yaml


def open_func():
with Path.open(Path("./config.yaml")) as f:
return yaml.load(f, Loader=yaml.FullLoader)


def test_open_func(mocker):
mocker.patch("pathlib.Path.open", mocker.mock_open(read_data="test_config.yaml"))
conf = open_func()

assert isinstance(conf, dict)

编辑:
为了更接近我的现实世界问题,我提供了以下代码。我有一个类 TryToMock ,这基本上需要两个文件作为输入。方法 load_files只需加载这些文件(实际上是 .yaml 文件)并返回输出。这些 .yaml 文件实际上是一些配置文件。

在我的单元测试中,我将调用 TryToMock多次通过 pytest 的 parametrize .因此,我想通过 fixture 加载原始配置文件。 .然后我就可以 monkeypatch我在运行之前的各种测试中的一些条目 load_files .

为了不再加载原始文件,我需要模拟 Path.open函数在 TryToMock .我想通过 monkeypatched yaml 文件(即以 dict 的形式)。困难在于我必须区分这两个文件。那就是我不能简单地 mock Path.open具有相同文件内容的函数。
# TryToMock.py

from pathlib import Path
import yaml

# In my current working folder, I have to .yaml files containing the following
# content for illustrative purpose:
#
# file1.yaml = {'name': 'test1', 'file_type': 'yaml'}
# file2.yaml = {'schema': 'test2', 'currencies': ['EUR', 'USD', 'JPY']}


class TryToMock:
def __init__(self, file_to_mock_1, file_to_mock_2):
self._file_to_mock_1 = file_to_mock_1
self._file_to_mock_2 = file_to_mock_2

def load_files(self):
with Path.open(self._file_to_mock_1) as f:
file1 = yaml.load(f, Loader=yaml.FullLoader)

with Path.open(self._file_to_mock_2) as f:
file2 = yaml.load(f, Loader=yaml.FullLoader)

return file1, file2




# test_TryToMock.py

import os
from pathlib import Path

import pytest
import yaml

from tests import TryToMock


def yaml_files_for_test(yaml_content):
names = {"file1.yaml": file1_content, "file2.yaml": file2_content}
return os.path.join("./", names[os.path.basename(yaml_content)])


@pytest.fixture(scope="module")
def file1_content():
with Path.open(Path("./file1.yaml")) as f:
return yaml.load(f, Loader=yaml.FullLoader)


@pytest.fixture(scope="module")
def file2_content():
with Path.open(Path("./file2.yaml")) as f:
return yaml.load(f, Loader=yaml.FullLoader)


def test_try_to_mock(file1_content, file2_content, monkeypatch, mocker):
file_1 = Path("./file1.yaml")
file_2 = Path("./file2.yaml")

m = TryToMock.TryToMock(file_to_mock_1=file_1, file_to_mock_2=file_2)

# Change some items
monkeypatch.setitem(file1_content, "file_type", "json")

# Mocking - How does it work when I would like to use mock_open???
# How should the lambda function look like?
mocker.patch(
"pathlib.Path.open",
lambda x: mocker.mock_open(read_data=yaml_files_for_test(x)),
)

files = m.load_files()
assert files[0]["file_type"] == "json"

最佳答案

您必须将实际文件内容提供给 read_data mock_open 的论据.您可以在测试中创建数据:

test_yaml = """
foo:
bar:
- VAR: "MyVar"
"""

def test_open_func(mocker):
mocker.patch("pathlib.Path.open", mocker.mock_open(read_data=test_yaml))
conf = open_func()
assert conf == {'foo': {'bar': [{'VAR': 'MyVar'}]}}

或者您可以从测试文件中读取数据:
def test_open_func(mocker):
with open("my_fixture_path/test.yaml") as f:
contents = f.read()
mocker.patch("pathlib.Path.open", mocker.mock_open(read_data=contents))
conf = open_func()
assert isinstance(conf, dict)

最后一种情况也可以重写以代替 path open 中的参数通过您的测试路径调用:
def test_open_func(mocker):
mocker.patch("pathlib.Path.open", lambda path: open("test.yaml"))
conf = open_func()
assert isinstance(conf, dict)

或者,如果您对不同的配置有不同的测试文件,例如:
def yaml_path_for_test(yaml_path):
names = {
"config.yaml": "test.yaml",
...
}
return os.path.join(my_fixture_path, names[os.path.basename(yaml_path)])

def test_open_func3(mocker):
mocker.patch("pathlib.Path.open", lambda path: open(yaml_path_for_test(path)))
conf = open_func()
assert isinstance(conf, dict)

这可能是您想要在测试代码中实现的目标。

更新:
这与问题的第二部分(编辑后)有关。如果您有模块范围的 fixture ,如问题中那样预加载 fixture 文件,您可以执行以下操作:
def test_open_func(mocker, file1_content, file2_content):
def yaml_files_for_test(path):
contents = {"file1.yaml": file1_content,
"file2.yaml": file2_content}
data = contents[os.path.basename(path)]
mock = mocker.mock_open(read_data=yaml.dump(data))
return mock.return_value

mocker.patch("pathlib.Path.open", yaml_files_for_test)
conf = open_func()
assert isinstance(conf, dict)

或者,如果您不想使用嵌套函数:
def yaml_files_for_test(path, mocker, content1, content2):
contents = {"file1.yaml": content1,
"file2.yaml": content2}
data = contents[os.path.basename(path)]
mock = mocker.mock_open(read_data=yaml.dump(data))
return mock.return_value


def test_open_func5(mocker, file1_content, file2_content):
mocker.patch("pathlib.Path.open",
lambda path: yaml_files_for_test(path, mocker,
file2_content, file2_content))
conf = open_func()
assert isinstance(conf, dict)

关于python - pytest-mock pathlib.Path.open,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61761758/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com