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

查看:128
本文介绍了使用两个不同的文件在类中的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对象(mock_open)的side_effect属性,并且不要忘记为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])


我发现了一种更优雅的方法来实现它内置的模拟开放"在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\nbb")
def test_interface_mapping_new(self, mo):
    handlers = (mo.return_value,mock_open(read_data="AA\nBB").return_value,)
    mo.side_effect = handlers
    with open("ppp") as f:
        self.assertEqual("aa\nbb",f.read())
    with open("ppp") as f:
        self.assertEqual("AA\nBB",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天全站免登陆