Reputation: 10269
I have a following function which needs to be unit tested.
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
Now, my all_fields_sheet is a sheet returned by xlrd module(Used to read Excel file).
So, basically I need to mock for following attributes nrows cell
How should I go abput it?
Upvotes: 1
Views: 3565
Reputation: 1123810
Just mock the calls and attributes directly on a mock object; adjust to cover your test needs:
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
By assigning a list to Mock.side_effect
you can control, in order, what calls to .cell()
return.
Afterwards, you can test if the right calls have been made with the various assertion methods. You could use the mock.call()
object to give precise expectations:
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)])
I used Mock.call_args_list
here to match an exact number of calls, directly to mock_sheet.cell
alone.
Demo, assuming that your read_all_fields()
function is already defined:
>>> 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
Alternatively, you could create a function for the mock_sheet.cell.side_effect
attribute, to return values from a 'sheet' you set up up front:
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
When side_effect
is a function, it is called whenever mock_sheet.cell()
is called, with the same arguments.
Upvotes: 5