使用两个不同文件的类中的 Python 模拟内置“打开" [英] Python mock builtin 'open' in a class using two different files

查看:25
本文介绍了使用两个不同文件的类中的 Python 模拟内置“打开"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当它们都使用上下文管理器时,我无法弄清楚如何模拟一个类中打开的两个文件.我知道如何使用这样的模拟模块为一个上下文管理的文件执行此操作:

I am having trouble figuring out how to mock two file opens in a class when they both use context managers. I know how to do it for one context-managed file using the mock module like this:

@patch('__builtin__.open')
def test_interface_mapping(self, mock_config):
        m = MagicMock(spec=file)
        handle = m.return_value.__enter__.return_value
        handle.__iter__.return_value = ('aa', 'bb')

我的问题是当一个类在同一个调用中打开两个不同的文件时如何做到这一点.在我的例子中,类 __init__() 将文件预加载到两个映射中.该类用于其他类.我想模拟这两个文件的加载以提供我的测试数据,以便可以针对我预加载的测试文件内容测试使用 IfAddrConfig 对象的其他类.

My problem is how to do this when a class opens two different files in the same call. In my case, the class __init__() preloads the files into two maps. This class is used in other classes. I want to mock the loading of these two files to provide my test data so that the other classes that use the IfAddrConfig object can be tested against my preloaded test file content.

这是一个我正在努力使用的类的示例,它在 __init__() 中加载两个文件,我想模拟这两个文件以加载我的测试注入文件内容.getInterfaceMap() 是经常调用的函数,所以我不希望每次调用都加载和解析文件,因此在 __init__() 中预加载地图一次.

Here's an example of the class I am struggling with that loads two files in __init__(), both of which I want to mock to load my test injected file contents. getInterfaceMap() is the function that is called frequently so I do not want that to be loading and parsing the files every call, hence the reason for preloading the maps in __init__() once.

class IfAddrConfig(object):
    def __init__(self):
        # Initialize the static maps once since they require file operations
        # that we do not want to be calling every time getInterfaceMap() is used
        self.settings_map = self.loadSettings()
        self.config_map = self.loadConfig()

    def loadConfig(self):
        config_map = defaultdict(dict)
        with open(os.path.join('some_path.cfg'), 'r') as stream:
            for line in stream:
                # Parse line and build up config_map entries
        return config_map

    def loadSettings(self):
        settings_map = {}
        with open('another_path.cfg', 'r') as stream:
            for line in stream:
                # Parse line and build up settings_map entries
        return settings_map

    def getInterfaceMap(self, interface):
        # Uses both the settings and config maps to finally create a composite map
        # that is returned to called
        interface_map = {}
        for values in self.config_map.values():
            # Accesss self.settings_map and combine/compare entries with
            # self.config_map values to build new composite mappings that
            # depend on supplied interface value
        return interface_map

推荐答案

你必须使用你的补丁 open 对象的 side_effect 属性 (mock_open) 并且不要忘记为 __exit__ 方法设置 return_value.

You must use side_effect attribute of your patched open object (mock_open) and don't forget to set the return_value for __exit__ method.

@patch('__builtin__.open', spec=open)
def test_interface_mapping(self, mock_open):
    handle1 = MagicMock()
    handle1.__enter__.return_value.__iter__.return_value = ('aa', 'bb')
    handle1.__exit__.return_value=False
    handle2 = MagicMock()
    handle2.__enter__.return_value.__iter__.return_value = ('AA', 'BB')
    handle2.__exit__.return_value=False
    mock_open.side_effect = (handle1, handle2)
    with open("ppp") as f:
        self.assertListEqual(["aa","bb"],[x for x in f])
    with open("ppp") as f:
        self.assertListEqual(["AA","BB"],[x for x in f])

<小时>

我找到了一种更优雅的方法来做到这一点 Mock builtin开放"在 contextlib 中使用时的函数


I found a much more elegant way to do it Mock builtin 'open" function when used in contextlib

所以你可以像这样重写测试

So you can rewrote test like

@patch('__builtin__.open', new_callable=mock_open, read_data="aa
bb")
def test_interface_mapping_new(self, mo):
    handlers = (mo.return_value,mock_open(read_data="AA
BB").return_value,)
    mo.side_effect = handlers
    with open("ppp") as f:
        self.assertEqual("aa
bb",f.read())
    with open("ppp") as f:
        self.assertEqual("AA
BB",f.read())

从 python 3.4 开始,您还可以使用 readline()、readlines() 而无需模拟其他任何内容.

And from python 3.4 you can use also readline(), readlines() without mocking anything else.

这篇关于使用两个不同文件的类中的 Python 模拟内置“打开"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆