Mocking open(file_name) in unit tests

2020-02-02 11:25发布

I have a source code that opens a csv file and sets up a header to value association. The source code is given below:

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() 

I am trying to mock the following statement

rack_type_file = open(rack_file) 

How do I mock open(...) function?

8条回答
甜甜的少女心
2楼-- · 2020-02-02 11:49
>>> class A(object):
...     def __init__(self):
...         self.x = open('test.py')
... 
>>> old_open = open
>>> def open(s):
...     return "test\n"
... 
>>> a = A()
>>> a.x
'test\n'
>>> open = old_open
>>> a = A()
>>> a.x
<open file 'test.py', mode 'r' at 0xb7736230>
查看更多
疯言疯语
3楼-- · 2020-02-02 11:52

I took the liberty of re-writing your sample function:

Assume your function is located in a file named code.py

# code.py
import csv

import logging


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_file = source
    attributes_list = []

    try:
        rack_type_file = open(rack_file)
    except IOError, (errno, strerror):
        logging.error("I/O error(%s): %s", errno, strerror)
    else:
        reader = csv.DictReader(rack_type_file, delimiter=',')
        attributes_list = [line for line in reader]   # list of dictionaries
        rack_type_file.close()

    return attributes_list

A simple test case would be:

# your test file
import __builtin__
import unittest
import contextlib
from StringIO import StringIO

import mox

import code


@contextlib.contextmanager
def mox_replayer(mox_instance):
    mox_instance.ReplayAll()
    yield
    mox_instance.VerifyAll()


class TestParseCSVFile(unittest.TestCase):

    def setUp(self):
        self.mox = mox.Mox()

    def tearDown(self):
        self.mox.UnsetStubs()

    def test_parse_csv_file_returns_list_of_dicts(self):
        TEST_FILE_NAME = 'foo.csv'

        self.mox.StubOutWithMock(__builtin__, 'open')
        open(TEST_FILE_NAME).AndReturn(StringIO("name,age\nfoo,13"))

        with mox_replayer(self.mox):
            result = code.ParseCsvFile(TEST_FILE_NAME)

        self.assertEqual(result, [{'age': '13', 'name': 'foo'}])  # works!


if __name__ == '__main__':
    unittest.main()

EDIT:

% /usr/bin/python2.6
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import __builtin__
>>> import mox
>>> mock = mox.Mox()
>>> mock.StubOutWithMock(__builtin__, 'open')
>>> mock.UnsetStubs()

Works fine on 2.6 using mox 0.53

查看更多
登录 后发表回答