模拟文件句柄

时间:2015-12-03 02:32:48

标签: python unit-testing

There's a couple of stack overflow posts out there talking about mocking the open call in Python.这很好但是如果函数接受文件句柄或流对象而不是文件路径,它对我没有帮助。

到目前为止,我一直在使用的一个解决方案是cStringIO个对象。然而,我遇到了一个问题。

如果我想测试我是否在某种类型的失败时正确记录文件名(例如,如果文件/流是空的并且您期望某种数据)

cStringIO
fd = cStringIO("")
fd.name = "testing/path" # Throws an AttributeError

我无法设置名称属性,因为cStringIOStringIO是分组类。

如果切换为使用open_mock

with mock.patch('__main__.open', mock.mock_open(read_data=''), create=True) as m:

我遇到了

AttributeError: Mock object has no attribute 'tell'

此时感觉我必须使用临时文件,但如果可能的话,我想避免实际调用文件系统。

如何在不必在文件系统上创建实际文件的情况下测试接收文件句柄的函数?

2 个答案:

答案 0 :(得分:1)

您可以使用Mock.return_value

为模拟对象显式设置tell属性
import mock

def function_under_test(f):
    f.tell()  # => 0
    f.read()
    f.tell()  # => 0
    return f.name

with mock.patch('__main__.open', mock.mock_open(read_data=''), create=True) as m:
    with open('/tmp/1') as f:
        f.name = '/tmp/1'
        f.tell.return_value = 0
        assert function_under_test(f) == '/tmp/1'

答案 1 :(得分:0)

我沿着创建一个继承自StringIO的类的道路前进。我花了很多时间才想承认在Python2.7中,StringIO是一个旧样式类。

class MockFile(StringIO, object):
    """This is a work around for the fact that StringIO is a slotted class and
    doesn't have a name attribute.
    """
    name = None
    def __init__(self, name, buffer_ = None):
        super(MockFile, self).__init__(buffer_)
        self.name = name