16

我正在使用python-mock来模拟文件打开调用。我希望能够以这种方式传递假数据,这样我就可以验证read()正在调用以及使用测试数据,而不会在测试中触及文件系统。

这是我到目前为止所得到的:

file_mock = MagicMock(spec=file)
file_mock.read.return_value = 'test'

with patch('__builtin__.open', create=True) as mock_open:
    mock_open.return_value = file_mock

    with open('x') as f:
        print f.read()

正如我所假设的那样,它的输出是<mock.Mock object at 0x8f4aaec>intead 的。'test'我在构建这个模拟时做错了什么?

编辑:

看起来像这样:

with open('x') as f:
     f.read()

还有这个:

f = open('x')
f.read()

是不同的对象。使用 mock 作为上下文管理器使其返回一个 new Mock,而直接调用它会返回我在mock_open.return_value. 有任何想法吗?

4

3 回答 3

27

在 Python 3 中,模式很简单:

>>> import unittest.mock as um
>>> with um.patch('builtins.open', um.mock_open(read_data='test')):
...     with open('/dev/null') as f:
...         print(f.read())
...
test
>>>

(是的,您甚至可以模拟 /dev/null 来返回文件内容。)

于 2016-04-08T00:05:23.423 回答
12

StringIO对于已经实现文件接口的对象,这听起来像是一个很好的用例。也许你可以制作一个file_mock = MagicMock(spec=file, wraps=StringIO('test')). 或者你可以让你的函数接受一个类似文件的对象并传递它StringIO而不是一个真实的文件,避免需要丑陋的猴子补丁。

你看过模拟文档吗?

http://www.voidspace.org.uk/python/mock/compare.html#mocking-the-builtin-open-used-as-a-context-manager

于 2012-01-05T17:46:47.267 回答
2

以@tbc0 答案为基础,支持 Python 2 和 3(多版本测试有助于端口 2 到 3):

import sys
module_ = "builtins"
module_ = module_ if module_ in sys.modules else '__builtin__'

try:
    import unittest.mock as mock
except (ImportError,) as e:
    import mock 

with mock.patch('%s.open' % module_, mock.mock_open(read_data='test')):
    with open('/dev/null') as f:
        print(f.read())
于 2018-07-07T01:27:37.607 回答