如何模拟对象属性和复杂的字段和方法?

时间:2016-07-28 14:02:02

标签: python python-2.7 unit-testing mocking

我有以下功能,需要进行单元测试。

def read_all_fields(all_fields_sheet):
    entries = []

    for row_index in xrange(2, all_fields_sheet.nrows):
        d = {'size' : all_fields_sheet.cell(row_index,0).value,\
             'type' : all_fields_sheet.cell(row_index,1).value,\
             'hotslide' : all_fields_sheet.cell(row_index,3).value}
        entries.append((all_fields_sheet.cell(row_index,2).value,d))

    return entries

现在,我的all_fields_sheet是xlrd模块返回的工作表(用于读取Excel文件)。

所以,基本上我需要模拟以下属性 NROWS 细胞

我该怎么去输?

1 个答案:

答案 0 :(得分:3)

直接在模拟对象上模拟调用和属性;调整以满足您的测试需求:

mock_sheet = MagicMock()
mock_sheet.nrows = 3  # loop once
cells = [
    MagicMock(value=42),     # row_index, 0
    MagicMock(value='foo'),  # row_index, 1
    MagicMock(value='bar'),  # row_index, 3
    MagicMock(value='spam'), # row_index, 2
]
mock_sheet.cell.side_effect = cells

通过将列表分配到Mock.side_effect,您可以按顺序控制对.cell()的回复。

之后,您可以测试是否使用各种断言方法进行了正确的调用。您可以使用mock.call() object给出精确的期望:

result = read_all_fields(mock_sheet)
self.assertEqual(
    result, 
    [('spam', {'size': 42, 'type': 'foo', 'hotslide': 'bar'})]
)

self.assertEqual(
    mock_sheet.cell.call_args_list,
    [call(2, 0), call(2, 1), call(2, 3), call(2, 2)])

我在这里使用Mock.call_args_list来匹配确切的呼叫数量,直接与mock_sheet.cell进行匹配。

演示,假设已经定义了read_all_fields()函数:

>>> from unittest.mock import MagicMock, call
>>> mock_sheet = MagicMock()
>>> mock_sheet.nrows = 3  # loop once
>>> cells = [
...     MagicMock(value=42),     # row_index, 0
...     MagicMock(value='foo'),  # row_index, 1
...     MagicMock(value='bar'),  # row_index, 3
...     MagicMock(value='spam'), # row_index, 2
... ]
>>> mock_sheet.cell.side_effect = cells
>>> result = read_all_fields(mock_sheet)
>>> result == [('spam', {'size': 42, 'type': 'foo', 'hotslide': 'bar'})]
True
>>> mock_sheet.cell.call_args_list == [call(2, 0), call(2, 1), call(2, 3), call(2, 2)]
True

或者,您可以为mock_sheet.cell.side_effect属性创建一个函数,以便从您预先设置的“工作表”中返回值:

cells = [[42, 'foo', 'spam', 'bar']]  # 1 row
def mock_cells(row, cell):
    return MagicMock(value=cells[row - 2][cell])
mock_sheet.cell.side_effect = mock_cells

side_effect是函数时,只要调用mock_sheet.cell(),就会调用它,并使用相同的参数。