单元测试中的模拟打开(文件名)

2024-05-19 18:48:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个源代码,它打开一个csv文件并设置一个头 价值关联。源代码如下:

def ParseCsvFile(source): 
  """Parse the csv file. 
  Args: 
    source: file to be parsed

  Returns: the list of dictionary entities; each dictionary contains
             attribute to value mapping or its equivalent. 
  """ 
  global rack_file 
  rack_type_file = None 
  try: 
    rack_file = source 
    rack_type_file = open(rack_file)  # Need to mock this line.
    headers = rack_type_file.readline().split(',') 
    length = len(headers) 
    reader = csv.reader(rack_type_file, delimiter=',') 
    attributes_list=[] # list of dictionaries. 
    for line in reader: 
      # More process to happeng. Converting the rack name to sequence. 
      attributes_list.append(dict((headers[i],
                                   line[i]) for i in range(length))) 
    return attributes_list 
  except IOError, (errno, strerror): 
    logging.error("I/O error(%s): %s" % (errno, strerror)) 
  except IndexError, (errno, strerror): 
    logging.error('Index Error(%s), %s' %(errno, strerror)) 
  finally: 
    rack_type_file.close() 

我在模仿下面的说法

rack_type_file = open(rack_file) 

如何模拟open(…)函数?


Tags: csvthetosourcetypelineopenattributes
3条回答

诚然,这是一个老问题,因此有些答案已经过时了。

在当前版本的mock库中,有一个方便的函数正是为此目的而设计的。其工作原理如下:

>>> from mock import mock_open
>>> m = mock_open()
>>> with patch('__main__.open', m, create=True):
...     with open('foo', 'w') as h:
...         h.write('some stuff')
...
>>> m.mock_calls
[call('foo', 'w'),
 call().__enter__(),
 call().write('some stuff'),
 call().__exit__(None, None, None)]
>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')

文档是here

要模拟使用mox打开的内置函数,请使用__builtin__模块:

import __builtin__ # unlike __builtins__ this must be imported
m = mox.Mox()
m.StubOutWithMock(__builtin__, 'open')
open('ftphelp.yml', 'rb').AndReturn(StringIO("fake file content"))     
m.ReplayAll()
# call the code you want to test that calls `open`
m.VerifyAll()
m.UnsetStubs()

注意__builtins__并不总是一个模块,它可以是dict类型,请使用__builtin__(没有“s”)模块来引用系统内置方法。

有关__builtin__模块的详细信息:http://docs.python.org/library/builtin.html

有两种方法我喜欢这样做,视情况而定。

如果您的单元测试将直接调用ParseCsvFile,我将向ParseCsvFile添加一个新的kwarg:

def ParseCsvFile(source, open=open): 
    # ...
    rack_type_file = open(rack_file)  # Need to mock this line.

然后,您的单元测试可以通过一个不同的open_func来完成模拟。

如果您的单元测试调用其他函数,而这些函数又调用ParseCsvFile,那么只为测试传递open_func是很难看的。在这种情况下,我将使用mock module。这允许您按名称更改函数并用模拟对象替换它。

# code.py
def open_func(name):
    return open(name)

def ParseCsvFile(source):
    # ...
    rack_type_file = open_func(rack_file)  # Need to mock this line.

# test.py
import unittest
import mock
from StringIO import StringIO

@mock.patch('code.open_func')
class ParseCsvTest(unittest.TestCase):
    def test_parse(self, open_mock):
        open_mock.return_value = StringIO("my,example,input")
        # ...

相关问题 更多 >